Skip to main content

ipnetwork/
ipv6.rs

1use std::{convert::TryFrom, fmt, net::Ipv6Addr, str::FromStr};
2
3use crate::{
4    error::IpNetworkError,
5    parse::{cidr_parts, parse_prefix},
6};
7
8const IPV6_BITS: u8 = 128;
9const IPV6_SEGMENT_BITS: u8 = 16;
10
11/// Represents a network range where the IP addresses are of v6
12#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
13pub struct Ipv6Network {
14    addr: Ipv6Addr,
15    prefix: u8,
16}
17
18#[cfg(feature = "serde")]
19impl<'de> serde::Deserialize<'de> for Ipv6Network {
20    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
21    where
22        D: serde::Deserializer<'de>,
23    {
24        let s = <String>::deserialize(deserializer)?;
25        Ipv6Network::from_str(&s).map_err(serde::de::Error::custom)
26    }
27}
28
29#[cfg(feature = "serde")]
30impl serde::Serialize for Ipv6Network {
31    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
32    where
33        S: serde::Serializer,
34    {
35        serializer.collect_str(self)
36    }
37}
38
39#[cfg(feature = "schemars")]
40impl schemars::JsonSchema for Ipv6Network {
41    fn schema_name() -> std::borrow::Cow<'static, str> {
42        std::borrow::Cow::Borrowed("Ipv6Network")
43    }
44
45    fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
46        schemars::json_schema!({
47            "type": "string",
48            "pattern": concat!(
49                r#"^("#,
50                r#"([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}"#,
51                r#"|([0-9a-fA-F]{1,4}:){1,7}:"#,
52                r#"|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}"#,
53                r#"|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}"#,
54                r#"|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}"#,
55                r#"|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}"#,
56                r#"|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}"#,
57                r#"|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})"#,
58                r#"|:((:[0-9a-fA-F]{1,4}){1,7}|:)"#,
59                r#"|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}"#,
60                r#"|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])"#,
61                r#"|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])"#,
62                r#"")[/](12[0-8]|1[0-1][0-9]|[0-9]?[0-9])$"#,
63            ),
64            "x-rust-type": "ipnetwork::Ipv6Network"
65        })
66    }
67}
68
69impl Ipv6Network {
70    /// Constructs a new `Ipv6Network` from any `Ipv6Addr` and a prefix denoting the network size.
71    ///
72    /// If the prefix is larger than 128 this will return an `IpNetworkError::InvalidPrefix`.
73    pub const fn new(addr: Ipv6Addr, prefix: u8) -> Result<Ipv6Network, IpNetworkError> {
74        match Ipv6Network::new_checked(addr, prefix) {
75            Some(a) => Ok(a),
76            None => Err(IpNetworkError::InvalidPrefix),
77        }
78    }
79
80    /// Constructs a new `Ipv6Network` from any `Ipv6Addr`, and a prefix denoting the network size.
81    ///
82    /// If the prefix is larger than 128 this will return `None`. This is useful in const contexts,
83    /// where [`Option::unwrap`] may be called to trigger a compile-time error in case the prefix
84    /// is an unexpected value.
85    ///
86    /// # Examples
87    ///
88    /// ```
89    /// use std::net::Ipv6Addr;
90    /// use ipnetwork::Ipv6Network;
91    ///
92    /// const PREFIX: u8 = 64;
93    /// const ADDR: Ipv6Addr = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
94    ///
95    /// // Okay!
96    /// const NETWORK: Ipv6Network = Ipv6Network::new_checked(ADDR, PREFIX).unwrap();
97    /// assert_eq!(NETWORK.prefix(), PREFIX);
98    /// ```
99    ///
100    /// ```should_panic
101    /// use std::net::Ipv6Addr;
102    /// use ipnetwork::Ipv6Network;
103    ///
104    /// // Prefix is greater than 128.
105    /// const PREFIX: u8 = 128 + 1;
106    /// const ADDR: Ipv6Addr = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
107    ///
108    /// // This fails!
109    /// const NETWORK: Option<Ipv6Network> = Ipv6Network::new_checked(ADDR, PREFIX);
110    /// assert_eq!(NETWORK.unwrap().prefix(), PREFIX);
111    /// ```
112    pub const fn new_checked(addr: Ipv6Addr, prefix: u8) -> Option<Ipv6Network> {
113        if prefix > IPV6_BITS {
114            None
115        } else {
116            Some(Ipv6Network {
117                addr,
118                prefix,
119            })
120        }
121    }
122
123    /// Constructs a new `Ipv6Network` from a network address and a network mask.
124    ///
125    /// If the netmask is not valid this will return an `IpNetworkError::InvalidPrefix`.
126    pub fn with_netmask(netaddr: Ipv6Addr, netmask: Ipv6Addr) -> Result<Self, IpNetworkError> {
127        let prefix = ipv6_mask_to_prefix(netmask)?;
128        let net = Self {
129            addr: netaddr,
130            prefix,
131        };
132        Ok(net)
133    }
134
135    /// Returns an iterator over `Ipv6Network`. Each call to `next` will return the next
136    /// `Ipv6Addr` in the given network. `None` will be returned when there are no more
137    /// addresses.
138    ///
139    /// # Warning
140    ///
141    /// This can return up to 2^128 addresses, which will take a _long_ time to iterate over.
142    pub fn iter(&self) -> Ipv6NetworkIterator {
143        let dec = u128::from(self.addr);
144        let max = u128::MAX;
145        let prefix = self.prefix;
146
147        let mask = max.checked_shl(u32::from(IPV6_BITS - prefix)).unwrap_or(0);
148        let start: u128 = dec & mask;
149
150        let mask = max.checked_shr(u32::from(prefix)).unwrap_or(0);
151        let end: u128 = dec | mask;
152
153        Ipv6NetworkIterator {
154            next: Some(start),
155            end,
156        }
157    }
158
159    pub const fn ip(&self) -> Ipv6Addr {
160        self.addr
161    }
162
163    pub const fn prefix(&self) -> u8 {
164        self.prefix
165    }
166
167    /// Checks if the given `Ipv6Network` is a subnet of the other.
168    pub fn is_subnet_of(self, other: Ipv6Network) -> bool {
169        other.ip() <= self.ip() && other.broadcast() >= self.broadcast()
170    }
171
172    /// Checks if the given `Ipv6Network` is a supernet of the other.
173    pub fn is_supernet_of(self, other: Ipv6Network) -> bool {
174        other.is_subnet_of(self)
175    }
176
177    /// Checks if the given `Ipv6Network` is partly contained in other.
178    pub fn overlaps(self, other: Ipv6Network) -> bool {
179        other.contains(self.ip())
180            || other.contains(self.broadcast())
181            || self.contains(other.ip())
182            || self.contains(other.broadcast())
183    }
184
185    /// Returns the mask for this `Ipv6Network`.
186    /// That means the `prefix` most significant bits will be 1 and the rest 0
187    ///
188    /// # Examples
189    ///
190    /// ```
191    /// use std::net::Ipv6Addr;
192    /// use ipnetwork::Ipv6Network;
193    ///
194    /// let net: Ipv6Network = "ff01::0".parse().unwrap();
195    /// assert_eq!(net.mask(), Ipv6Addr::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff));
196    /// let net: Ipv6Network = "ff01::0/32".parse().unwrap();
197    /// assert_eq!(net.mask(), Ipv6Addr::new(0xffff, 0xffff, 0, 0, 0, 0, 0, 0));
198    /// ```
199    pub const fn mask(&self) -> Ipv6Addr {
200        debug_assert!(self.prefix <= IPV6_BITS);
201
202        if self.prefix == 0 {
203            return Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
204        }
205        let mask = u128::MAX << (IPV6_BITS - self.prefix);
206        Ipv6Addr::from_bits(mask)
207    }
208
209    /// Returns the address of the network denoted by this `Ipv6Network`.
210    /// This means the lowest possible IPv6 address inside of the network.
211    ///
212    /// # Examples
213    ///
214    /// ```
215    /// use std::net::Ipv6Addr;
216    /// use ipnetwork::Ipv6Network;
217    ///
218    /// let net: Ipv6Network = "2001:db8::/96".parse().unwrap();
219    /// assert_eq!(net.network(), Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0));
220    /// ```
221    pub const fn network(&self) -> Ipv6Addr {
222        let mask = self.mask().to_bits();
223        let network = self.addr.to_bits() & mask;
224        Ipv6Addr::from_bits(network)
225    }
226
227    /// Returns the broadcast address of this `Ipv6Network`.
228    /// This means the highest possible IPv4 address inside of the network.
229    ///
230    /// # Examples
231    ///
232    /// ```
233    /// use std::net::Ipv6Addr;
234    /// use ipnetwork::Ipv6Network;
235    ///
236    /// let net: Ipv6Network = "2001:db8::/96".parse().unwrap();
237    /// assert_eq!(net.broadcast(), Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0xffff, 0xffff));
238    /// ```
239    pub const fn broadcast(&self) -> Ipv6Addr {
240        let mask = self.mask().to_bits();
241        let broadcast = self.addr.to_bits() | !mask;
242        Ipv6Addr::from_bits(broadcast)
243    }
244
245    /// Checks if a given `Ipv6Addr` is in this `Ipv6Network`
246    ///
247    /// # Examples
248    ///
249    /// ```
250    /// use std::net::Ipv6Addr;
251    /// use ipnetwork::Ipv6Network;
252    ///
253    /// let net: Ipv6Network = "ff01::0/32".parse().unwrap();
254    /// assert!(net.contains(Ipv6Addr::new(0xff01, 0, 0, 0, 0, 0, 0, 0x1)));
255    /// assert!(!net.contains(Ipv6Addr::new(0xffff, 0, 0, 0, 0, 0, 0, 0x1)));
256    /// ```
257    #[inline]
258    pub const fn contains(&self, ip: Ipv6Addr) -> bool {
259        let ip = ip.to_bits();
260        let net = self.network().to_bits();
261        let mask = self.mask().to_bits();
262        (ip & mask) == net
263    }
264
265    /// Returns number of possible host addresses in this `Ipv6Network`.
266    ///
267    /// # Examples
268    ///
269    /// ```
270    /// use std::net::Ipv6Addr;
271    /// use ipnetwork::Ipv6Network;
272    ///
273    /// let net: Ipv6Network = "ff01::0/32".parse().unwrap();
274    /// assert_eq!(net.size(), 79228162514264337593543950336);
275    ///
276    /// let tinynet: Ipv6Network = "ff01::0/128".parse().unwrap();
277    /// assert_eq!(tinynet.size(), 1);
278    /// ```
279    pub fn size(&self) -> u128 {
280        debug_assert!(self.prefix <= IPV6_BITS);
281
282        if self.prefix == 0 {
283            return u128::MAX;
284        }
285        1 << (IPV6_BITS - self.prefix)
286    }
287
288    /// Returns the `n`:th address within this network.
289    /// The addresses are indexed from 0 and `n` must be smaller than the size of the network.
290    ///
291    /// # Examples
292    ///
293    /// ```
294    /// use std::net::Ipv6Addr;
295    /// use ipnetwork::Ipv6Network;
296    ///
297    /// let net: Ipv6Network = "ff01::0/32".parse().unwrap();
298    /// assert_eq!(net.nth(0).unwrap(), "ff01::0".parse::<Ipv6Addr>().unwrap());
299    /// assert_eq!(net.nth(255).unwrap(), "ff01::ff".parse::<Ipv6Addr>().unwrap());
300    /// assert_eq!(net.nth(65538).unwrap(), "ff01::1:2".parse::<Ipv6Addr>().unwrap());
301    /// assert!(net.nth(net.size()).is_none());
302    /// ```
303    pub fn nth(self, n: u128) -> Option<Ipv6Addr> {
304        if n < self.size() {
305            let net = u128::from(self.network());
306            Some(Ipv6Addr::from(net + n))
307        } else {
308            None
309        }
310    }
311}
312
313/// Creates an `Ipv6Network` from parsing a string in CIDR notation.
314///
315/// # Examples
316///
317/// ```
318/// use std::net::Ipv6Addr;
319/// use ipnetwork::Ipv6Network;
320///
321/// let new = Ipv6Network::new(Ipv6Addr::new(0xff01, 0, 0, 0x17, 0, 0, 0, 0x2), 65).unwrap();
322/// let from_cidr: Ipv6Network = "FF01:0:0:17:0:0:0:2/65".parse().unwrap();
323/// assert_eq!(new.ip(), from_cidr.ip());
324/// assert_eq!(new.prefix(), from_cidr.prefix());
325/// ```
326impl FromStr for Ipv6Network {
327    type Err = IpNetworkError;
328    fn from_str(s: &str) -> Result<Self, Self::Err> {
329        let (addr_str, prefix_str) = cidr_parts(s)?;
330        let addr = Ipv6Addr::from_str(addr_str)?;
331        let prefix = parse_prefix(prefix_str.unwrap_or(&IPV6_BITS.to_string()), IPV6_BITS)?;
332        Ipv6Network::new(addr, prefix)
333    }
334}
335
336impl TryFrom<&str> for Ipv6Network {
337    type Error = IpNetworkError;
338
339    fn try_from(s: &str) -> Result<Self, Self::Error> {
340        Ipv6Network::from_str(s)
341    }
342}
343
344impl From<Ipv6Addr> for Ipv6Network {
345    fn from(a: Ipv6Addr) -> Ipv6Network {
346        Ipv6Network {
347            addr: a,
348            prefix: 128,
349        }
350    }
351}
352
353#[derive(Clone, Debug)]
354pub struct Ipv6NetworkIterator {
355    next: Option<u128>,
356    end: u128,
357}
358
359impl Iterator for Ipv6NetworkIterator {
360    type Item = Ipv6Addr;
361
362    fn next(&mut self) -> Option<Ipv6Addr> {
363        let next = self.next?;
364        self.next = if next == self.end { None } else { Some(next + 1) };
365        Some(next.into())
366    }
367
368    fn size_hint(&self) -> (usize, Option<usize>) {
369        if let Some(n) = self.next {
370            let elms = (self.end - n + 1) as usize;
371            (elms, Some(elms))
372        } else {
373            (0, None)
374        }
375    }
376}
377
378impl IntoIterator for &'_ Ipv6Network {
379    type IntoIter = Ipv6NetworkIterator;
380    type Item = Ipv6Addr;
381    fn into_iter(self) -> Ipv6NetworkIterator {
382        self.iter()
383    }
384}
385
386impl fmt::Display for Ipv6Network {
387    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
388        write!(fmt, "{}/{}", self.ip(), self.prefix())
389    }
390}
391
392/// Converts a `Ipv6Addr` network mask into a prefix.
393/// If the mask is invalid this will return an `IpNetworkError::InvalidPrefix`.
394pub fn ipv6_mask_to_prefix(mask: Ipv6Addr) -> Result<u8, IpNetworkError> {
395    match ipv6_mask_to_prefix_checked(mask) {
396        Some(prefix) => Ok(prefix),
397        None => Err(IpNetworkError::InvalidPrefix),
398    }
399}
400
401/// Converts a `Ipv6Addr` network mask into a prefix.
402///
403/// If the mask is invalid this will return `None`. This is useful in const contexts where
404/// [`Option::unwrap`] may be called to trigger a compile-time error if the prefix is invalid.
405pub const fn ipv6_mask_to_prefix_checked(mask: Ipv6Addr) -> Option<u8> {
406    let mask = mask.segments();
407
408    // Count the number of set bits from the start of the address
409    let mut prefix = 0;
410    let mut i = 0;
411    while i < mask.len() {
412        let segment = mask[i];
413        i += 1;
414        if segment == 0xffff {
415            prefix += IPV6_SEGMENT_BITS;
416        } else if segment == 0 {
417            // Prefix finishes on a segment boundary
418            break;
419        } else {
420            let prefix_bits = (!segment).leading_zeros() as u8;
421            // Check that the remainder of the bits are all unset
422            if segment << prefix_bits != 0 {
423                return None;
424            }
425            prefix += prefix_bits;
426            break;
427        }
428    }
429
430    // Now check all the remaining bits are unset
431    while i < mask.len() {
432        let segment = mask[i];
433        i += 1;
434        if segment != 0 {
435            return None;
436        }
437    }
438
439    Some(prefix)
440}
441
442#[cfg(test)]
443mod test {
444    use std::{collections::HashMap, net::Ipv6Addr};
445
446    use super::*;
447
448    #[test]
449    fn create_v6() {
450        let cidr = Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 24).unwrap();
451        assert_eq!(cidr.prefix(), 24);
452    }
453
454    #[test]
455    fn parse_netmask_broken_v6() {
456        assert_eq!(
457            "FF01:0:0:17:0:0:0:2/255.255.255.0".parse::<Ipv6Network>(),
458            Err(IpNetworkError::InvalidPrefix)
459        );
460    }
461
462    #[test]
463    fn create_v6_invalid_prefix() {
464        let cidr = Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 129);
465        assert!(cidr.is_err());
466    }
467
468    #[test]
469    fn create_checked_v6() {
470        let cidr = Ipv6Network::new_checked(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 24).unwrap();
471        assert_eq!(cidr.prefix(), 24);
472    }
473
474    #[test]
475    #[should_panic]
476    fn try_create_invalid_checked_v6() {
477        Ipv6Network::new_checked(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 129).unwrap();
478    }
479
480    #[test]
481    fn parse_v6() {
482        let cidr: Ipv6Network = "::1/0".parse().unwrap();
483        assert_eq!(cidr.ip(), Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
484        assert_eq!(cidr.prefix(), 0);
485    }
486
487    #[test]
488    fn parse_v6_2() {
489        let cidr: Ipv6Network = "FF01:0:0:17:0:0:0:2/64".parse().unwrap();
490        assert_eq!(cidr.ip(), Ipv6Addr::new(0xff01, 0, 0, 0x17, 0, 0, 0, 0x2));
491        assert_eq!(cidr.prefix(), 64);
492    }
493
494    #[test]
495    fn parse_v6_noprefix() {
496        let cidr: Ipv6Network = "::1".parse().unwrap();
497        assert_eq!(cidr.ip(), Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
498        assert_eq!(cidr.prefix(), 128);
499    }
500
501    #[test]
502    fn parse_v6_fail_addr() {
503        let cidr: Option<Ipv6Network> = "2001::1::/8".parse().ok();
504        assert_eq!(None, cidr);
505    }
506
507    #[test]
508    fn parse_v6_fail_prefix() {
509        let cidr: Option<Ipv6Network> = "::1/129".parse().ok();
510        assert_eq!(None, cidr);
511    }
512
513    #[test]
514    fn parse_v6_fail_two_slashes() {
515        let cidr: Option<Ipv6Network> = "::1/24/".parse().ok();
516        assert_eq!(None, cidr);
517    }
518
519    #[test]
520    fn mask_v6() {
521        let cidr = Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0), 40).unwrap();
522        let mask = cidr.mask();
523        assert_eq!(mask, Ipv6Addr::new(0xffff, 0xffff, 0xff00, 0, 0, 0, 0, 0));
524    }
525
526    #[test]
527    fn contains_v6() {
528        let cidr = Ipv6Network::new(Ipv6Addr::new(0xff01, 0, 0, 0x17, 0, 0, 0, 0x2), 65).unwrap();
529        let ip = Ipv6Addr::new(0xff01, 0, 0, 0x17, 0x7fff, 0, 0, 0x2);
530        assert!(cidr.contains(ip));
531    }
532
533    #[test]
534    fn not_contains_v6() {
535        let cidr = Ipv6Network::new(Ipv6Addr::new(0xff01, 0, 0, 0x17, 0, 0, 0, 0x2), 65).unwrap();
536        let ip = Ipv6Addr::new(0xff01, 0, 0, 0x17, 0xffff, 0, 0, 0x2);
537        assert!(!cidr.contains(ip));
538    }
539
540    #[test]
541    fn v6_mask_to_prefix() {
542        let mask = Ipv6Addr::new(0xffff, 0xffff, 0xffff, 0, 0, 0, 0, 0);
543        let prefix = ipv6_mask_to_prefix(mask).unwrap();
544        assert_eq!(prefix, 48);
545    }
546
547    #[test]
548    fn invalid_v6_mask_to_prefix() {
549        let mask = Ipv6Addr::new(0, 0, 0xffff, 0xffff, 0, 0, 0, 0);
550        let prefix = ipv6_mask_to_prefix(mask);
551        assert!(prefix.is_err());
552    }
553
554    #[test]
555    fn ipv6network_with_netmask() {
556        {
557            // Positive test-case.
558            let addr = Ipv6Addr::new(0xff01, 0, 0, 0x17, 0, 0, 0, 0x2);
559            let mask = Ipv6Addr::new(0xffff, 0xffff, 0xffff, 0, 0, 0, 0, 0);
560            let net = Ipv6Network::with_netmask(addr, mask).unwrap();
561            let expected = Ipv6Network::new(Ipv6Addr::new(0xff01, 0, 0, 0x17, 0, 0, 0, 0x2), 48).unwrap();
562            assert_eq!(net, expected);
563        }
564        {
565            // Negative test-case.
566            let addr = Ipv6Addr::new(0xff01, 0, 0, 0x17, 0, 0, 0, 0x2);
567            let mask = Ipv6Addr::new(0, 0, 0xffff, 0xffff, 0, 0, 0, 0);
568            Ipv6Network::with_netmask(addr, mask).unwrap_err();
569        }
570    }
571
572    #[test]
573    fn iterator_v6() {
574        let cidr: Ipv6Network = "2001:db8::/126".parse().unwrap();
575        let mut iter = cidr.iter();
576        assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0), iter.next().unwrap());
577        assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1), iter.next().unwrap());
578        assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 2), iter.next().unwrap());
579        assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 3), iter.next().unwrap());
580        assert_eq!(None, iter.next());
581    }
582
583    #[test]
584    fn iterator_v6_tiny() {
585        let cidr: Ipv6Network = "2001:db8::/128".parse().unwrap();
586        let mut iter = cidr.iter();
587        assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0), iter.next().unwrap());
588        assert_eq!(None, iter.next());
589    }
590
591    #[test]
592    fn iterator_v6_huge() {
593        let cidr: Ipv6Network = "2001:db8::/0".parse().unwrap();
594        let mut iter = cidr.iter();
595        assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0), iter.next().unwrap());
596        assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), iter.next().unwrap());
597        assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 2), iter.next().unwrap());
598    }
599
600    #[test]
601    fn iterator_v6_size_hint() {
602        let cidr: Ipv6Network = "2001:db8::/128".parse().unwrap();
603        let mut iter = cidr.iter();
604        assert_eq!((1, Some(1)), iter.size_hint());
605        assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0), iter.next().unwrap());
606        assert_eq!((0, None), iter.size_hint());
607    }
608
609    #[test]
610    fn network_v6() {
611        let cidr: Ipv6Network = "2001:db8::0/96".parse().unwrap();
612        let net = cidr.network();
613        let expected: Ipv6Addr = "2001:db8::".parse().unwrap();
614        assert_eq!(net, expected);
615    }
616
617    #[test]
618    fn broadcast_v6() {
619        let cidr: Ipv6Network = "2001:db8::0/96".parse().unwrap();
620        let net = cidr.broadcast();
621        let expected: Ipv6Addr = "2001:db8::ffff:ffff".parse().unwrap();
622        assert_eq!(net, expected);
623    }
624
625    #[test]
626    fn size_v6() {
627        let cidr: Ipv6Network = "2001:db8::0/96".parse().unwrap();
628        assert_eq!(cidr.size(), 4294967296);
629    }
630
631    #[test]
632    fn ipv6network_from_ipv6addr() {
633        let net = Ipv6Network::from(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
634        let expected = Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 128).unwrap();
635        assert_eq!(net, expected);
636    }
637
638    #[test]
639    fn test_send() {
640        fn assert_send<T: Send>() {}
641        assert_send::<Ipv6Network>();
642    }
643
644    #[test]
645    fn test_sync() {
646        fn assert_sync<T: Sync>() {}
647        assert_sync::<Ipv6Network>();
648    }
649
650    // Tests from cpython https://github.com/python/cpython/blob/e9bc4172d18db9c182d8e04dd7b033097a994c06/Lib/test/test_ipaddress.py
651    #[test]
652    fn test_is_subnet_of() {
653        let mut test_cases: HashMap<(Ipv6Network, Ipv6Network), bool> = HashMap::new();
654
655        test_cases.insert(("2000:999::/56".parse().unwrap(), "2000:aaa::/48".parse().unwrap()), false);
656        test_cases.insert(("2000:aaa::/56".parse().unwrap(), "2000:aaa::/48".parse().unwrap()), true);
657        test_cases.insert(("2000:bbb::/56".parse().unwrap(), "2000:aaa::/48".parse().unwrap()), false);
658        test_cases.insert(("2000:aaa::/48".parse().unwrap(), "2000:aaa::/56".parse().unwrap()), false);
659
660        for (key, val) in test_cases.iter() {
661            let (src, dest) = (key.0, key.1);
662            assert_eq!(src.is_subnet_of(dest), *val, "testing with {src} and {dest}");
663        }
664    }
665
666    #[test]
667    fn test_is_supernet_of() {
668        let mut test_cases: HashMap<(Ipv6Network, Ipv6Network), bool> = HashMap::new();
669
670        test_cases.insert(("2000:999::/56".parse().unwrap(), "2000:aaa::/48".parse().unwrap()), false);
671        test_cases.insert(("2000:aaa::/56".parse().unwrap(), "2000:aaa::/48".parse().unwrap()), false);
672        test_cases.insert(("2000:bbb::/56".parse().unwrap(), "2000:aaa::/48".parse().unwrap()), false);
673        test_cases.insert(("2000:aaa::/48".parse().unwrap(), "2000:aaa::/56".parse().unwrap()), true);
674
675        for (key, val) in test_cases.iter() {
676            let (src, dest) = (key.0, key.1);
677            assert_eq!(src.is_supernet_of(dest), *val, "testing with {src} and {dest}");
678        }
679    }
680
681    #[test]
682    fn test_overlaps() {
683        let other: Ipv6Network = "2001:DB8:ACAD::1/64".parse().unwrap();
684        let other2: Ipv6Network = "2001:DB8:ACAD::20:2/64".parse().unwrap();
685
686        assert!(other2.overlaps(other));
687    }
688
689    #[test]
690    fn edges() {
691        let low: Ipv6Network = "::0/120".parse().unwrap();
692        let low_addrs: Vec<Ipv6Addr> = low.iter().collect();
693        assert_eq!(256, low_addrs.len());
694
695        let high: Ipv6Network = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00/120".parse().unwrap();
696        let high_addrs: Vec<Ipv6Addr> = high.iter().collect();
697        assert_eq!(256, high_addrs.len());
698    }
699
700    #[test]
701    fn test_nth_ipv6() {
702        let net = Ipv6Network::from_str("ff01::/32").unwrap();
703
704        assert_eq!(net.nth(0).unwrap(), Ipv6Addr::from_str("ff01:0:0:0:0:0:0:0").unwrap());
705        assert_eq!(net.nth(255).unwrap(), Ipv6Addr::from_str("ff01::ff").unwrap());
706        assert_eq!(net.nth(65538).unwrap(), Ipv6Addr::from_str("ff01::1:2").unwrap());
707        assert_eq!(net.nth(net.size()), None);
708    }
709
710    #[test]
711    fn test_mask_with_prefix_0() {
712        let network: Ipv6Network = "0::/0".parse().unwrap();
713        let mask = network.mask();
714        assert_eq!(mask, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
715    }
716
717    #[test]
718    fn test_size_with_prefix_0() {
719        let network: Ipv6Network = "0::/0".parse().unwrap();
720        assert_eq!(network.size(), u128::MAX);
721    }
722}