ip_network/
ipv6_network.rs

1use std::fmt;
2use std::net::Ipv6Addr;
3use std::str::FromStr;
4use std::hash::{Hash, Hasher};
5use crate::{IpNetworkError, IpNetworkParseError};
6use crate::helpers;
7use crate::iterator;
8use std::collections::HashMap;
9use std::collections::hash_map::Entry;
10
11/// IPv6 Multicast Address Scopes.
12#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
13pub enum Ipv6MulticastScope {
14    InterfaceLocal,
15    LinkLocal,
16    RealmLocal,
17    AdminLocal,
18    SiteLocal,
19    OrganizationLocal,
20    Global,
21}
22
23/// IPv6 Network.
24#[derive(Clone, Copy, Debug, Eq, PartialOrd, Ord)]
25pub struct Ipv6Network {
26    pub(crate) network_address: Ipv6Addr,
27    pub(crate) netmask: u8,
28}
29
30impl Ipv6Network {
31    /// IPv6 address length in bits.
32    pub const LENGTH: u8 = 128;
33
34    /// Default route that contains all IP addresses, IP network ::/0
35    pub const DEFAULT_ROUTE: Self = Self {
36        network_address: Ipv6Addr::UNSPECIFIED,
37        netmask: 0,
38    };
39
40    /// Constructs new `Ipv6Network` based on [`Ipv6Addr`] and `netmask`.
41    ///
42    /// Returns error if netmask is bigger than 128 or if host bits are set in `network_address`.
43    ///
44    /// [`Ipv6Addr`]: https://doc.rust-lang.org/std/net/struct.Ipv6Addr.html
45    ///
46    /// # Examples
47    ///
48    /// ```
49    /// use std::net::Ipv6Addr;
50    /// use ip_network::Ipv6Network;
51    ///
52    /// let ip = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
53    /// let ip_network = Ipv6Network::new(ip, 32)?;
54    /// assert_eq!(ip_network.network_address(), ip);
55    /// assert_eq!(ip_network.netmask(), 32);
56    /// # Ok::<(), ip_network::IpNetworkError>(())
57    /// ```
58    #[allow(clippy::new_ret_no_self)]
59    pub fn new(network_address: Ipv6Addr, netmask: u8) -> Result<Self, IpNetworkError> {
60        if netmask > Self::LENGTH {
61            return Err(IpNetworkError::NetmaskError(netmask));
62        }
63
64        if u128::from(network_address).trailing_zeros() < u32::from(Self::LENGTH - netmask) {
65            return Err(IpNetworkError::HostBitsSet);
66        }
67
68        Ok(Self {
69            network_address,
70            netmask,
71        })
72    }
73
74    /// Constructs new `Ipv6Network` based on [`Ipv6Addr`] and `netmask` with truncating host bits
75    /// from given `network_address`.
76    ///
77    /// Returns error if netmask is bigger than 128.
78    ///
79    /// [`Ipv6Addr`]: https://doc.rust-lang.org/std/net/struct.Ipv6Addr.html
80    ///
81    /// # Examples
82    ///
83    /// ```
84    /// use std::net::Ipv6Addr;
85    /// use ip_network::Ipv6Network;
86    ///
87    /// let ip = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 1, 0, 0);
88    /// let ip_network = Ipv6Network::new_truncate(ip, 32)?;
89    /// assert_eq!(ip_network.network_address(), Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0));
90    /// assert_eq!(ip_network.netmask(), 32);
91    /// # Ok::<(), ip_network::IpNetworkError>(())
92    /// ```
93    pub fn new_truncate(network_address: Ipv6Addr, netmask: u8) -> Result<Self, IpNetworkError> {
94        if netmask > Self::LENGTH {
95            return Err(IpNetworkError::NetmaskError(netmask));
96        }
97
98        let network_address_u128 = u128::from(network_address) & helpers::bite_mask_u128(netmask);
99        let network_address = Ipv6Addr::from(network_address_u128);
100
101        Ok(Self {
102            network_address,
103            netmask,
104        })
105    }
106
107    /// Returns network IP address (first address in range).
108    ///
109    /// # Examples
110    ///
111    /// ```
112    /// use std::net::Ipv6Addr;
113    /// use ip_network::Ipv6Network;
114    ///
115    /// let ip = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
116    /// let ip_network = Ipv6Network::new(ip, 32)?;
117    /// assert_eq!(ip_network.network_address(), ip);
118    /// # Ok::<(), ip_network::IpNetworkError>(())
119    /// ```
120    #[inline]
121    pub fn network_address(&self) -> Ipv6Addr {
122        self.network_address
123    }
124
125    /// Returns last IP address in range. Similar as `broadcast_address` for IPv4.
126    ///
127    /// # Examples
128    ///
129    /// ```
130    /// use std::net::Ipv6Addr;
131    /// use ip_network::Ipv6Network;
132    ///
133    /// let ip = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
134    /// let ip_network = Ipv6Network::new(ip, 32)?;
135    /// assert_eq!(ip_network.last_address(), Ipv6Addr::new(0x2001, 0xdb8, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff));
136    /// # Ok::<(), ip_network::IpNetworkError>(())
137    /// ```
138    pub fn last_address(&self) -> Ipv6Addr {
139        Ipv6Addr::from(u128::from(self.network_address) | !helpers::bite_mask_u128(self.netmask))
140    }
141
142    /// Returns network mask.
143    ///
144    /// # Examples
145    ///
146    /// ```
147    /// use std::net::Ipv6Addr;
148    /// use ip_network::Ipv6Network;
149    ///
150    /// let ip = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
151    /// let ip_network = Ipv6Network::new(ip, 32)?;
152    /// assert_eq!(ip_network.netmask(), 32);
153    /// # Ok::<(), ip_network::IpNetworkError>(())
154    /// ```
155    #[inline]
156    pub fn netmask(&self) -> u8 {
157        self.netmask
158    }
159
160    /// Returns [`true`] if given [`IPv6Addr`] is inside this network.
161    ///
162    /// [`true`]: https://doc.rust-lang.org/std/primitive.bool.html
163    /// [`Ipv6Addr`]: https://doc.rust-lang.org/std/net/struct.Ipv6Addr.html
164    ///
165    /// # Examples
166    ///
167    /// ```
168    /// use std::net::Ipv6Addr;
169    /// use ip_network::Ipv6Network;
170    ///
171    /// let ip_network = Ipv6Network::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0), 64)?;
172    /// assert!(ip_network.contains(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)));
173    /// assert!(!ip_network.contains(Ipv6Addr::new(0x2001, 0xdb9, 0, 0, 0, 0, 0, 0)));
174    /// # Ok::<(), ip_network::IpNetworkError>(())
175    /// ```
176    pub fn contains(&self, ip: Ipv6Addr) -> bool {
177        let truncated_ip = u128::from(ip) & helpers::bite_mask_u128(self.netmask);
178        truncated_ip == u128::from(self.network_address)
179    }
180
181    /// Returns network with smaller netmask by one. If netmask is already zero, `None` will be returned.
182    ///
183    /// # Examples
184    ///
185    /// ```
186    /// use std::net::Ipv6Addr;
187    /// use ip_network::Ipv6Network;
188    ///
189    /// let network = Ipv6Network::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0), 32)?;
190    /// assert_eq!(network.supernet(), Some(Ipv6Network::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0), 31)?));
191    /// # Ok::<(), ip_network::IpNetworkError>(())
192    /// ```
193    pub fn supernet(&self) -> Option<Self> {
194        if self.netmask == 0 {
195            None
196        } else {
197            Some(Self::new_truncate(self.network_address, self.netmask - 1).unwrap())
198        }
199    }
200
201    /// Returns `Ipv6NetworkIterator` over networks with netmask bigger one.
202    /// If netmask is already 128, empty iterator will be returned.
203    ///
204    /// # Examples
205    ///
206    /// ```
207    /// use std::net::Ipv6Addr;
208    /// use ip_network::Ipv6Network;
209    ///
210    /// let ip_network = Ipv6Network::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0), 32)?;
211    /// let mut iterator = ip_network.subnets();
212    /// assert_eq!(iterator.next().unwrap(), Ipv6Network::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0), 33)?);
213    /// assert_eq!(iterator.last().unwrap(), Ipv6Network::new(Ipv6Addr::new(0x2001, 0xdb8, 0x8000, 0, 0, 0, 0, 0), 33)?);
214    /// # Ok::<(), ip_network::IpNetworkError>(())
215    /// ```
216    pub fn subnets(&self) -> iterator::Ipv6NetworkIterator {
217        let new_netmask = ::std::cmp::min(self.netmask + 1, Self::LENGTH);
218        iterator::Ipv6NetworkIterator::new(*self, new_netmask)
219    }
220
221    /// Returns `Ipv6NetworkIterator` over networks with defined netmask. Because [`len()`] method
222    /// returns `usize` and number of networks can be bigger than `usize`, you can use `real_len()` method
223    /// to get exact number of networks.
224    ///
225    /// [`len()`]: https://doc.rust-lang.org/std/iter/trait.ExactSizeIterator.html#method.len
226    ///
227    /// # Panics
228    ///
229    /// This method panics when prefix is bigger than 128 or when prefix is lower or equal than netmask.
230    ///
231    /// # Examples
232    ///
233    /// ```
234    /// use std::net::Ipv6Addr;
235    /// use ip_network::Ipv6Network;
236    ///
237    /// let network = Ipv6Network::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0), 32)?;
238    /// let mut iterator = network.subnets_with_prefix(33);
239    /// assert_eq!(2, iterator.real_len());
240    /// assert_eq!(iterator.next().unwrap(), Ipv6Network::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0), 33)?);
241    /// assert_eq!(iterator.last().unwrap(), Ipv6Network::new(Ipv6Addr::new(0x2001, 0xdb8, 0x8000, 0, 0, 0, 0, 0), 33)?);
242    /// # Ok::<(), ip_network::IpNetworkError>(())
243    /// ```
244    pub fn subnets_with_prefix(&self, prefix: u8) -> iterator::Ipv6NetworkIterator {
245        iterator::Ipv6NetworkIterator::new(*self, prefix)
246    }
247
248    /// Returns [`true`] for the default route network (::/0), that contains all IPv6 addresses.
249    ///
250    /// [`true`]: https://doc.rust-lang.org/std/primitive.bool.html
251    ///
252    /// # Examples
253    ///
254    /// ```
255    /// use std::net::Ipv6Addr;
256    /// use ip_network::Ipv6Network;
257    ///
258    /// assert!(Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0), 0)?.is_default_route());
259    /// # Ok::<(), ip_network::IpNetworkError>(())
260    /// ```
261    pub fn is_default_route(&self) -> bool {
262        self.netmask == 0
263    }
264
265    /// Returns [`true`] for the special 'unspecified' network (::/128).
266    ///
267    /// This property is defined in [IETF RFC 4291].
268    ///
269    /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
270    /// [`true`]: https://doc.rust-lang.org/std/primitive.bool.html
271    ///
272    /// # Examples
273    ///
274    /// ```
275    /// use std::net::Ipv6Addr;
276    /// use ip_network::Ipv6Network;
277    ///
278    /// assert!(!Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff), 128)?.is_unspecified());
279    /// assert!(Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0), 128)?.is_unspecified());
280    /// # Ok::<(), ip_network::IpNetworkError>(())
281    /// ```
282    pub fn is_unspecified(&self) -> bool {
283        self.netmask == Self::LENGTH && self.network_address.is_unspecified()
284    }
285
286    /// Returns [`true`] if this is a loopback network (::1/128).
287    ///
288    /// This property is defined in [IETF RFC 4291].
289    ///
290    /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
291    /// [`true`]: https://doc.rust-lang.org/std/primitive.bool.html
292    ///
293    /// # Examples
294    ///
295    /// ```
296    /// use std::net::Ipv6Addr;
297    /// use ip_network::Ipv6Network;
298    ///
299    /// assert!(Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1), 128)?.is_loopback());
300    /// assert!(!Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff), 128)?.is_loopback());
301    /// # Ok::<(), ip_network::IpNetworkError>(())
302    /// ```
303    pub fn is_loopback(&self) -> bool {
304        self.network_address.is_loopback()
305    }
306
307    /// Returns [`true`] if the address appears to be globally routable.
308    ///
309    /// The following return [`false`]:
310    ///
311    /// - the loopback network
312    /// - link-local, site-local, and unique local unicast networks
313    /// - interface-, link-, realm-, admin- and site-local multicast networks
314    ///
315    /// [`true`]: https://doc.rust-lang.org/std/primitive.bool.html
316    /// [`false`]: https://doc.rust-lang.org/std/primitive.bool.html
317    ///
318    /// # Examples
319    ///
320    /// ```
321    /// use std::net::Ipv6Addr;
322    /// use ip_network::Ipv6Network;
323    ///
324    /// assert!(Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff), 128)?.is_global());
325    /// assert!(!Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1), 128)?.is_global());
326    /// assert!(Ipv6Network::new(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1), 128)?.is_global());
327    /// # Ok::<(), ip_network::IpNetworkError>(())
328    /// ```
329    pub fn is_global(&self) -> bool {
330        match self.multicast_scope() {
331            Some(Ipv6MulticastScope::Global) => true,
332            None => self.is_unicast_global(),
333            _ => false,
334        }
335    }
336
337    /// Returns [`true`] if this is a part of unique local network (fc00::/7).
338    ///
339    /// This property is defined in [IETF RFC 4193].
340    ///
341    /// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193
342    /// [`true`]: https://doc.rust-lang.org/std/primitive.bool.html
343    ///
344    /// # Examples
345    ///
346    /// ```
347    /// use std::net::Ipv6Addr;
348    /// use ip_network::Ipv6Network;
349    ///
350    /// assert!(Ipv6Network::new(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0), 16)?.is_unique_local());
351    /// assert!(!Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff), 128)?.is_unique_local());
352    /// # Ok::<(), ip_network::IpNetworkError>(())
353    /// ```
354    pub fn is_unique_local(&self) -> bool {
355        (self.network_address.segments()[0] & 0xfe00) == 0xfc00 && self.netmask >= 7
356    }
357
358    /// Returns [`true`] if the network is part of unicast and link-local (fe80::/10).
359    ///
360    /// This property is defined in [IETF RFC 4291].
361    ///
362    /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
363    /// [`true`]: https://doc.rust-lang.org/std/primitive.bool.html
364    ///
365    /// # Examples
366    ///
367    /// ```
368    /// use std::net::Ipv6Addr;
369    /// use ip_network::Ipv6Network;
370    ///
371    /// assert!(Ipv6Network::new(Ipv6Addr::new(0xfe8a, 0, 0, 0, 0, 0, 0, 0), 16)?.is_unicast_link_local());
372    /// assert!(!Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff), 128)?.is_unicast_link_local());
373    /// # Ok::<(), ip_network::IpNetworkError>(())
374    /// ```
375    pub fn is_unicast_link_local(&self) -> bool {
376        (self.network_address.segments()[0] & 0xffc0) == 0xfe80 && self.netmask >= 10
377    }
378
379    /// Returns [`true`] if this is a deprecated unicast site-local network (fec0::/10).
380    ///
381    /// [`true`]: https://doc.rust-lang.org/std/primitive.bool.html
382    ///
383    /// # Examples
384    ///
385    /// ```
386    /// use std::net::Ipv6Addr;
387    /// use ip_network::Ipv6Network;
388    ///
389    /// assert!(Ipv6Network::new(Ipv6Addr::new(0xfec2, 0, 0, 0, 0, 0, 0, 0), 16)?.is_unicast_site_local());
390    /// assert!(!Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff), 128)?.is_unicast_site_local());
391    /// # Ok::<(), ip_network::IpNetworkError>(())
392    /// ```
393    pub fn is_unicast_site_local(&self) -> bool {
394        (self.network_address.segments()[0] & 0xffc0) == 0xfec0 && self.netmask >= 10
395    }
396
397    /// Returns [`true`] if this is a part of network reserved for documentation (2001:db8::/32).
398    ///
399    /// This property is defined in [IETF RFC 3849].
400    ///
401    /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849
402    /// [`true`]: https://doc.rust-lang.org/std/primitive.bool.html
403    ///
404    /// # Examples
405    ///
406    /// ```
407    /// use std::net::Ipv6Addr;
408    /// use ip_network::Ipv6Network;
409    ///
410    /// assert!(Ipv6Network::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0), 32)?.is_documentation());
411    /// assert!(!Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff), 128)?.is_documentation());
412    /// # Ok::<(), ip_network::IpNetworkError>(())
413    /// ```
414    pub fn is_documentation(&self) -> bool {
415        let segments = self.network_address.segments();
416        segments[0] == 0x2001 && segments[1] == 0xdb8 && self.netmask >= 32
417    }
418
419    /// Returns [`true`] if the network is a globally routable unicast network.
420    ///
421    /// The following return [`false`]:
422    ///
423    /// - the loopback network
424    /// - the link-local network
425    /// - the (deprecated) site-local network
426    /// - unique local network
427    /// - the unspecified network
428    /// - the network range reserved for documentation
429    ///
430    /// [`true`]: https://doc.rust-lang.org/std/primitive.bool.html
431    /// [`false`]: https://doc.rust-lang.org/std/primitive.bool.html
432    ///
433    /// # Examples
434    ///
435    /// ```
436    /// use std::net::Ipv6Addr;
437    /// use ip_network::Ipv6Network;
438    ///
439    /// assert!(!Ipv6Network::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0), 32)?.is_unicast_global());
440    /// assert!(Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff), 128)?.is_unicast_global());
441    /// # Ok::<(), ip_network::IpNetworkError>(())
442    /// ```
443    pub fn is_unicast_global(&self) -> bool {
444        !self.is_multicast()
445            && !self.is_loopback()
446            && !self.is_unicast_link_local()
447            && !self.is_unicast_site_local()
448            && !self.is_unique_local()
449            && !self.is_unspecified()
450            && !self.is_documentation()
451    }
452
453    /// Returns [`true`] if this is a part of multicast network (ff00::/8).
454    ///
455    /// This property is defined by [IETF RFC 4291].
456    ///
457    /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
458    /// [`true`]: https://doc.rust-lang.org/std/primitive.bool.html
459    ///
460    /// # Examples
461    ///
462    /// ```
463    /// use std::net::Ipv6Addr;
464    /// use ip_network::Ipv6Network;
465    ///
466    /// assert!(Ipv6Network::new(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0), 8)?.is_multicast());
467    /// assert!(!Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff), 128)?.is_multicast());
468    /// # Ok::<(), ip_network::IpNetworkError>(())
469    /// ```
470    pub fn is_multicast(&self) -> bool {
471        self.network_address.is_multicast()
472    }
473
474    /// Returns the network's multicast scope if the network is multicast.
475    ///
476    /// These scopes are defined in [IETF RFC 7346].
477    ///
478    /// [IETF RFC 7346]: https://tools.ietf.org/html/rfc7346
479    ///
480    /// # Examples
481    ///
482    /// ```
483    /// use std::net::Ipv6Addr;
484    /// use ip_network::{Ipv6Network, Ipv6MulticastScope};
485    ///
486    /// assert_eq!(Ipv6Network::new(Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0), 32)?.multicast_scope(),
487    ///                              Some(Ipv6MulticastScope::Global));
488    /// assert_eq!(Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff), 128)?.multicast_scope(), None);
489    /// # Ok::<(), ip_network::IpNetworkError>(())
490    /// ```
491    pub fn multicast_scope(&self) -> Option<Ipv6MulticastScope> {
492        if self.is_multicast() && self.netmask >= 16 {
493            match self.network_address.segments()[0] & 0x000f {
494                1 => Some(Ipv6MulticastScope::InterfaceLocal),
495                2 => Some(Ipv6MulticastScope::LinkLocal),
496                3 => Some(Ipv6MulticastScope::RealmLocal),
497                4 => Some(Ipv6MulticastScope::AdminLocal),
498                5 => Some(Ipv6MulticastScope::SiteLocal),
499                8 => Some(Ipv6MulticastScope::OrganizationLocal),
500                14 => Some(Ipv6MulticastScope::Global),
501                _ => None,
502            }
503        } else {
504            None
505        }
506    }
507
508    /// Converts string in format X:X::X/Y (CIDR notation) to `Ipv6Network`, but truncating host bits.
509    ///
510    /// # Examples
511    ///
512    /// ```
513    /// use std::net::Ipv6Addr;
514    /// use ip_network::Ipv6Network;
515    ///
516    /// let ip_network = Ipv6Network::from_str_truncate("2001:db8::1/32")?;
517    /// assert_eq!(ip_network.network_address(), Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0));
518    /// assert_eq!(ip_network.netmask(), 32);
519    /// # Ok::<(), ip_network::IpNetworkParseError>(())
520    /// ```
521    pub fn from_str_truncate(s: &str) -> Result<Self, IpNetworkParseError> {
522        let (ip, netmask) =
523            helpers::split_ip_netmask(s).ok_or(IpNetworkParseError::InvalidFormatError)?;
524
525        let network_address =
526            Ipv6Addr::from_str(ip).map_err(|_| IpNetworkParseError::AddrParseError)?;
527        let netmask =
528            u8::from_str(netmask).map_err(|_| IpNetworkParseError::InvalidNetmaskFormat)?;
529
530        Self::new_truncate(network_address, netmask).map_err(IpNetworkParseError::IpNetworkError)
531    }
532
533    /// Return an iterator of the collapsed Ipv6Networks.
534    ///
535    /// Implementation of this method was inspired by Python [`ipaddress.collapse_addresses`]
536    ///
537    /// [`ipaddress.collapse_addresses`]: https://docs.python.org/3/library/ipaddress.html#ipaddress.collapse_addresses
538    ///
539    /// # Examples
540    ///
541    /// ```
542    /// use std::net::Ipv6Addr;
543    /// use ip_network::Ipv6Network;
544    /// use std::str::FromStr;
545    ///
546    /// let collapsed = Ipv6Network::collapse_addresses(&[
547    ///     Ipv6Network::from_str("2001::/120")?,
548    ///     Ipv6Network::from_str("2001::/96")?,
549    /// ]);
550    ///
551    /// assert_eq!(Ipv6Network::from_str("2001::/96")?, collapsed[0]);
552    /// # Ok::<(), ip_network::IpNetworkParseError>(())
553    /// ```
554    pub fn collapse_addresses(addresses: &[Self]) -> Vec<Self> {
555        let mut subnets = HashMap::new();
556
557        let mut to_merge = addresses.to_vec();
558        while let Some(net) = to_merge.pop() {
559            let supernet = net.supernet().unwrap_or(Ipv6Network::DEFAULT_ROUTE);
560            match subnets.entry(supernet) {
561                Entry::Vacant(vacant) => {
562                    vacant.insert(net);
563                }
564                Entry::Occupied(occupied) => {
565                    if *occupied.get() != net {
566                        occupied.remove();
567                        to_merge.push(supernet);
568                    }
569                }
570            }
571        }
572
573        let mut output: Vec<Ipv6Network> = vec![];
574        let mut values = subnets.values().collect::<Vec<_>>();
575        values.sort_unstable();
576
577        for net in values {
578            if let Some(last) = output.last() {
579                // Since they are sorted, last.network_address <= net.network_address is a given.
580                if last.last_address() >= net.last_address() {
581                    continue;
582                }
583            }
584            output.push(*net);
585        }
586        output
587    }
588}
589
590impl fmt::Display for Ipv6Network {
591    /// Converts `Ipv6Network` to string in format X:X::X/Y (CIDR notation).
592    ///
593    /// # Examples
594    ///
595    /// ```
596    /// use std::net::Ipv6Addr;
597    /// use ip_network::Ipv6Network;
598    ///
599    /// let ip_network = Ipv6Network::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0), 32)?;
600    /// assert_eq!(ip_network.to_string(), "2001:db8::/32");
601    /// # Ok::<(), ip_network::IpNetworkError>(())
602    /// ```
603    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
604        write!(f, "{}/{}", self.network_address, self.netmask)
605    }
606}
607
608impl FromStr for Ipv6Network {
609    type Err = IpNetworkParseError;
610
611    /// Converts string in format X:X::X/Y (CIDR notation) to `Ipv6Network`.
612    ///
613    /// # Examples
614    ///
615    /// ```
616    /// use std::net::Ipv6Addr;
617    /// use ip_network::Ipv6Network;
618    /// use std::str::FromStr;
619    ///
620    /// let ip_network = Ipv6Network::from_str("2001:db8::/32")?;
621    /// assert_eq!(ip_network.network_address(), Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0));
622    /// assert_eq!(ip_network.netmask(), 32);
623    /// # Ok::<(), ip_network::IpNetworkParseError>(())
624    /// ```
625    fn from_str(s: &str) -> Result<Ipv6Network, IpNetworkParseError> {
626        let (ip, netmask) =
627            helpers::split_ip_netmask(s).ok_or(IpNetworkParseError::InvalidFormatError)?;
628
629        let network_address =
630            Ipv6Addr::from_str(ip).map_err(|_| IpNetworkParseError::AddrParseError)?;
631        let netmask =
632            u8::from_str(netmask).map_err(|_| IpNetworkParseError::InvalidNetmaskFormat)?;
633
634        Self::new(network_address, netmask).map_err(IpNetworkParseError::IpNetworkError)
635    }
636}
637
638impl From<Ipv6Addr> for Ipv6Network {
639    /// Converts `Ipv6Addr` to `Ipv6Network` with netmask 128.
640    #[inline]
641    fn from(ip: Ipv6Addr) -> Self {
642        Self {
643            network_address: ip,
644            netmask: Self::LENGTH,
645        }
646    }
647}
648
649impl PartialEq for Ipv6Network {
650    #[inline]
651    fn eq(&self, other: &Ipv6Network) -> bool {
652        self.netmask == other.netmask && self.network_address == other.network_address
653    }
654}
655
656impl Hash for Ipv6Network {
657    fn hash<H: Hasher>(&self, state: &mut H) {
658        self.network_address.hash(state);
659        self.netmask.hash(state);
660    }
661}
662
663#[cfg(test)]
664mod tests {
665    use std::net::Ipv6Addr;
666    use crate::{Ipv6Network, IpNetworkError, Ipv6MulticastScope};
667    use std::str::FromStr;
668    use std::hash::{Hash, Hasher};
669    use std::collections::hash_map::DefaultHasher;
670
671    fn return_test_ipv6_network() -> Ipv6Network {
672        Ipv6Network::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0), 32).unwrap()
673    }
674
675    #[test]
676    fn default_route() {
677        let network = Ipv6Network::DEFAULT_ROUTE;
678        assert!(network.is_default_route());
679    }
680
681    #[test]
682    fn new() {
683        let ip = Ipv6Addr::new(0xfc00, 0, 0, 0, 0, 0, 0, 0);
684        let network = Ipv6Network::new(ip, 7).unwrap();
685        assert_eq!(
686            network.network_address(),
687            Ipv6Addr::new(0xfc00, 0, 0, 0, 0, 0, 0, 0)
688        );
689        assert_eq!(network.netmask(), 7);
690    }
691
692    #[test]
693    fn new_invalid_netmask() {
694        let ip = Ipv6Addr::new(0xfc00, 0, 0, 0, 0, 0, 0, 0);
695        let network = Ipv6Network::new(ip, 129);
696        assert!(network.is_err());
697        assert_eq!(IpNetworkError::NetmaskError(129), network.unwrap_err());
698    }
699
700    #[test]
701    fn new_truncate_invalid_netmask() {
702        let ip = Ipv6Addr::new(0xfc00, 0, 0, 0, 0, 0, 0, 0);
703        let network = Ipv6Network::new_truncate(ip, 129);
704        assert!(network.is_err());
705        assert_eq!(IpNetworkError::NetmaskError(129), network.unwrap_err());
706    }
707
708    #[test]
709    fn contains() {
710        let ip_network = return_test_ipv6_network();
711        assert!(!ip_network.contains(Ipv6Addr::new(
712            0x2001, 0x0db7, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff
713        )));
714        assert!(ip_network.contains(Ipv6Addr::new(0x2001, 0x0db8, 0, 0, 0, 0, 0, 0)));
715        assert!(ip_network.contains(Ipv6Addr::new(
716            0x2001, 0x0db8, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff
717        )));
718        assert!(!ip_network.contains(Ipv6Addr::new(0x2001, 0x0db9, 0, 0, 0, 0, 0, 0)));
719    }
720
721    #[test]
722    fn supernet() {
723        let ip_network = return_test_ipv6_network();
724        assert_eq!(
725            ip_network.supernet(),
726            Some(Ipv6Network::new(Ipv6Addr::new(0x2001, 0x0db8, 0, 0, 0, 0, 0, 0), 31).unwrap())
727        );
728    }
729
730    #[test]
731    fn supernet_none() {
732        let ipv6_network = Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0), 0).unwrap();
733        assert_eq!(None, ipv6_network.supernet());
734    }
735
736    #[test]
737    fn subnets() {
738        let mut subnets = return_test_ipv6_network().subnets();
739        assert_eq!(subnets.len(), 2);
740        assert_eq!(
741            subnets.next().unwrap(),
742            Ipv6Network::new(Ipv6Addr::new(0x2001, 0x0db8, 0, 0, 0, 0, 0, 0), 33).unwrap()
743        );
744        assert_eq!(
745            subnets.next().unwrap(),
746            Ipv6Network::new(Ipv6Addr::new(0x2001, 0x0db8, 0x8000, 0, 0, 0, 0, 0), 33).unwrap()
747        );
748        assert!(subnets.next().is_none());
749    }
750
751    #[test]
752    fn subnets_with_prefix() {
753        let ip_network = return_test_ipv6_network();
754        let mut subnets = ip_network.subnets_with_prefix(34);
755        assert_eq!(subnets.len(), 4);
756        assert_eq!(
757            subnets.next().unwrap(),
758            Ipv6Network::new(Ipv6Addr::new(0x2001, 0x0db8, 0x0000, 0, 0, 0, 0, 0), 34).unwrap()
759        );
760        assert_eq!(
761            subnets.next().unwrap(),
762            Ipv6Network::new(Ipv6Addr::new(0x2001, 0x0db8, 0x4000, 0, 0, 0, 0, 0), 34).unwrap()
763        );
764        assert_eq!(
765            subnets.next().unwrap(),
766            Ipv6Network::new(Ipv6Addr::new(0x2001, 0x0db8, 0x8000, 0, 0, 0, 0, 0), 34).unwrap()
767        );
768        assert_eq!(
769            subnets.next().unwrap(),
770            Ipv6Network::new(Ipv6Addr::new(0x2001, 0x0db8, 0xc000, 0, 0, 0, 0, 0), 34).unwrap()
771        );
772        assert!(subnets.next().is_none());
773    }
774
775    #[test]
776    fn is_loopback() {
777        assert!(
778            Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1), 128)
779                .unwrap()
780                .is_loopback()
781        )
782    }
783
784    #[test]
785    fn is_global() {
786        assert!("2c0f:fb50:4000::/36"
787            .parse::<Ipv6Network>()
788            .unwrap()
789            .is_global());
790        assert!("2001:4860:4000::/36"
791            .parse::<Ipv6Network>()
792            .unwrap()
793            .is_global());
794    }
795
796    #[test]
797    fn multicast_scope() {
798        let multicast_scope =
799            |network: &str| network.parse::<Ipv6Network>().unwrap().multicast_scope();
800
801        assert_eq!(None, multicast_scope("ff02::/15"));
802        assert_eq!(None, multicast_scope("fff2::/15"));
803        assert_eq!(
804            Some(Ipv6MulticastScope::InterfaceLocal),
805            multicast_scope("ff01::/16")
806        );
807        assert_eq!(
808            Some(Ipv6MulticastScope::InterfaceLocal),
809            multicast_scope("fff1::/16")
810        );
811        assert_eq!(
812            Some(Ipv6MulticastScope::LinkLocal),
813            multicast_scope("ff02::/16")
814        );
815        assert_eq!(
816            Some(Ipv6MulticastScope::LinkLocal),
817            multicast_scope("fff2::/16")
818        );
819        assert_eq!(
820            Some(Ipv6MulticastScope::RealmLocal),
821            multicast_scope("ff03::/16")
822        );
823        assert_eq!(
824            Some(Ipv6MulticastScope::RealmLocal),
825            multicast_scope("fff3::/16")
826        );
827        assert_eq!(
828            Some(Ipv6MulticastScope::AdminLocal),
829            multicast_scope("ff04::/16")
830        );
831        assert_eq!(
832            Some(Ipv6MulticastScope::AdminLocal),
833            multicast_scope("fff4::/16")
834        );
835        assert_eq!(
836            Some(Ipv6MulticastScope::SiteLocal),
837            multicast_scope("ff05::/16")
838        );
839        assert_eq!(
840            Some(Ipv6MulticastScope::SiteLocal),
841            multicast_scope("fff5::/16")
842        );
843        assert_eq!(
844            Some(Ipv6MulticastScope::OrganizationLocal),
845            multicast_scope("ff08::/16")
846        );
847        assert_eq!(
848            Some(Ipv6MulticastScope::OrganizationLocal),
849            multicast_scope("fff8::/16")
850        );
851        assert_eq!(
852            Some(Ipv6MulticastScope::Global),
853            multicast_scope("ff0e::/16")
854        );
855        assert_eq!(
856            Some(Ipv6MulticastScope::Global),
857            multicast_scope("fffe::/16")
858        );
859    }
860
861    #[test]
862    fn collapse_addresses() {
863        let addresses = [
864            Ipv6Network::from_str("2001::/100").unwrap(),
865            Ipv6Network::from_str("2001::/120").unwrap(),
866            Ipv6Network::from_str("2001::/96").unwrap(),
867        ];
868        let collapsed = Ipv6Network::collapse_addresses(&addresses);
869        assert_eq!(1, collapsed.len());
870        assert_eq!(Ipv6Network::from_str("2001::/96").unwrap(), collapsed[0]);
871    }
872
873    #[test]
874    fn parse() {
875        let ip_network: Ipv6Network = "2001:db8::/32".parse().unwrap();
876        assert_eq!(ip_network, return_test_ipv6_network());
877    }
878
879    #[test]
880    fn format() {
881        let ip_network = return_test_ipv6_network();
882        assert_eq!(ip_network.to_string(), "2001:db8::/32");
883    }
884
885    #[test]
886    fn from_ipv6addr() {
887        let ip = Ipv6Addr::new(0x2001, 0x0db8, 0xc000, 0, 0, 0, 0, 0);
888        let ipv6_network = Ipv6Network::from(ip);
889        assert_eq!(ip, ipv6_network.network_address());
890        assert_eq!(128, ipv6_network.netmask());
891    }
892
893    #[test]
894    fn hash() {
895        let network1 = Ipv6Network::from_str("2001::/100").unwrap();
896        let network2 = Ipv6Network::from_str("2001::/120").unwrap();
897
898        let mut hasher1 = DefaultHasher::new();
899        network1.hash(&mut hasher1);
900
901        let mut hasher2 = DefaultHasher::new();
902        network2.hash(&mut hasher2);
903
904        assert_ne!(hasher1.finish(), hasher2.finish());
905    }
906}