@@ -3,6 +3,8 @@ package maxminddb
33import (
44 "fmt"
55 "net/netip"
6+
7+ "iter"
68)
79
810// Internal structure used to keep track of nodes we still need to visit.
@@ -12,8 +14,8 @@ type netNode struct {
1214 pointer uint
1315}
1416
15- // Networks represents a set of subnets that we are iterating over.
16- type Networks struct {
17+ // networks represents a set of subnets that we are iterating over.
18+ type networks struct {
1719 err error
1820 reader * Reader
1921 nodes []netNode
@@ -27,12 +29,12 @@ var (
2729)
2830
2931// NetworksOption are options for Networks and NetworksWithin.
30- type NetworksOption func (* Networks )
32+ type NetworksOption func (* networks )
3133
3234// IncludeAliasedNetworks is an option for Networks and NetworksWithin
3335// that makes them iterate over aliases of the IPv4 subtree in an IPv6
3436// database, e.g., ::ffff:0:0/96, 2001::/32, and 2002::/16.
35- func IncludeAliasedNetworks (networks * Networks ) {
37+ func IncludeAliasedNetworks (networks * networks ) {
3638 networks .includeAliasedNetworks = true
3739}
3840
@@ -43,15 +45,11 @@ func IncludeAliasedNetworks(networks *Networks) {
4345// in an IPv6 database. This iterator will only iterate over these once by
4446// default. To iterate over all the IPv4 network locations, use the
4547// IncludeAliasedNetworks option.
46- func (r * Reader ) Networks (options ... NetworksOption ) * Networks {
47- var networks * Networks
48+ func (r * Reader ) Networks (options ... NetworksOption ) iter.Seq [Result ] {
4849 if r .Metadata .IPVersion == 6 {
49- networks = r .NetworksWithin (allIPv6 , options ... )
50- } else {
51- networks = r .NetworksWithin (allIPv4 , options ... )
50+ return r .NetworksWithin (allIPv6 , options ... )
5251 }
53-
54- return networks
52+ return r .NetworksWithin (allIPv4 , options ... )
5553}
5654
5755// NetworksWithin returns an iterator that can be used to traverse all networks
@@ -64,17 +62,49 @@ func (r *Reader) Networks(options ...NetworksOption) *Networks {
6462//
6563// If the provided prefix is contained within a network in the database, the
6664// iterator will iterate over exactly one network, the containing network.
67- func (r * Reader ) NetworksWithin (prefix netip.Prefix , options ... NetworksOption ) * Networks {
65+ func (r * Reader ) NetworksWithin (prefix netip.Prefix , options ... NetworksOption ) iter.Seq [Result ] {
66+ n := r .networksWithin (prefix , options ... )
67+ return func (yield func (Result ) bool ) {
68+ for n .next () {
69+ if n .err != nil {
70+ yield (Result {err : n .err })
71+ return
72+ }
73+
74+ ip := n .lastNode .ip
75+ if isInIPv4Subtree (ip ) {
76+ ip = v6ToV4 (ip )
77+ }
78+
79+ offset , err := r .resolveDataPointer (n .lastNode .pointer )
80+ ok := yield (Result {
81+ decoder : r .decoder ,
82+ ip : ip ,
83+ offset : uint (offset ),
84+ prefixLen : uint8 (n .lastNode .bit ),
85+ err : err ,
86+ })
87+ if ! ok {
88+ return
89+ }
90+ }
91+ if n .err != nil {
92+ yield (Result {err : n .err })
93+ }
94+ }
95+ }
96+
97+ func (r * Reader ) networksWithin (prefix netip.Prefix , options ... NetworksOption ) * networks {
6898 if r .Metadata .IPVersion == 4 && prefix .Addr ().Is6 () {
69- return & Networks {
99+ return & networks {
70100 err : fmt .Errorf (
71101 "error getting networks with '%s': you attempted to use an IPv6 network in an IPv4-only database" ,
72102 prefix ,
73103 ),
74104 }
75105 }
76106
77- networks := & Networks {reader : r }
107+ networks := & networks {reader : r }
78108 for _ , option := range options {
79109 option (networks )
80110 }
@@ -105,10 +135,10 @@ func (r *Reader) NetworksWithin(prefix netip.Prefix, options ...NetworksOption)
105135 return networks
106136}
107137
108- // Next prepares the next network for reading with the Network method. It
138+ // next prepares the next network for reading with the Network method. It
109139// returns true if there is another network to be processed and false if there
110140// are no more networks or if there is an error.
111- func (n * Networks ) Next () bool {
141+ func (n * networks ) next () bool {
112142 if n .err != nil {
113143 return false
114144 }
@@ -160,32 +190,6 @@ func (n *Networks) Next() bool {
160190 return false
161191}
162192
163- // Network returns the current network or an error if there is a problem
164- // decoding the data for the network. It takes a pointer to a result value to
165- // decode the network's data into.
166- func (n * Networks ) Network (result any ) (netip.Prefix , error ) {
167- if n .err != nil {
168- return netip.Prefix {}, n .err
169- }
170- if err := n .reader .retrieveData (n .lastNode .pointer , result ); err != nil {
171- return netip.Prefix {}, err
172- }
173-
174- ip := n .lastNode .ip
175- prefixLength := int (n .lastNode .bit )
176- if isInIPv4Subtree (ip ) {
177- ip = v6ToV4 (ip )
178- prefixLength -= 96
179- }
180-
181- return netip .PrefixFrom (ip , prefixLength ), nil
182- }
183-
184- // Err returns an error, if any, that was encountered during iteration.
185- func (n * Networks ) Err () error {
186- return n .err
187- }
188-
189193var ipv4SubtreeBoundary = netip .MustParseAddr ("::255.255.255.255" ).Next ()
190194
191195// isInIPv4Subtree returns true if the IP is in the database's IPv4 subtree.
0 commit comments