ipnetwork/
ipv6.rs

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