| //! Extensions to the standard IP address types for common operations. |
| //! |
| //! The [`IpAdd`], [`IpSub`], [`IpBitAnd`], [`IpBitOr`] traits extend |
| //! the `Ipv4Addr` and `Ipv6Addr` types with methods to perform these |
| //! operations. |
| |
| use std::cmp::Ordering::{Less, Equal}; |
| use std::iter::{FusedIterator, DoubleEndedIterator}; |
| use std::mem; |
| use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; |
| |
| /// Provides a `saturating_add()` method for `Ipv4Addr` and `Ipv6Addr`. |
| /// |
| /// Adding an integer to an IP address returns the modified IP address. |
| /// A `u32` may added to an IPv4 address and a `u128` may be added to |
| /// an IPv6 address. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use std::net::{Ipv4Addr, Ipv6Addr}; |
| /// use ipnet::IpAdd; |
| /// |
| /// let ip0: Ipv4Addr = "192.168.0.0".parse().unwrap(); |
| /// let ip1: Ipv4Addr = "192.168.0.5".parse().unwrap(); |
| /// let ip2: Ipv4Addr = "255.255.255.254".parse().unwrap(); |
| /// let max: Ipv4Addr = "255.255.255.255".parse().unwrap(); |
| /// |
| /// assert_eq!(ip0.saturating_add(5), ip1); |
| /// assert_eq!(ip2.saturating_add(1), max); |
| /// assert_eq!(ip2.saturating_add(5), max); |
| /// |
| /// let ip0: Ipv6Addr = "fd00::".parse().unwrap(); |
| /// let ip1: Ipv6Addr = "fd00::5".parse().unwrap(); |
| /// let ip2: Ipv6Addr = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe".parse().unwrap(); |
| /// let max: Ipv6Addr = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff".parse().unwrap(); |
| /// |
| /// assert_eq!(ip0.saturating_add(5), ip1); |
| /// assert_eq!(ip2.saturating_add(1), max); |
| /// assert_eq!(ip2.saturating_add(5), max); |
| /// ``` |
| pub trait IpAdd<RHS = Self> { |
| type Output; |
| fn saturating_add(self, rhs: RHS) -> Self::Output; |
| } |
| |
| /// Provides a `saturating_sub()` method for `Ipv4Addr` and `Ipv6Addr`. |
| /// |
| /// Subtracting an integer from an IP address returns the modified IP |
| /// address. A `u32` may be subtracted from an IPv4 address and a `u128` |
| /// may be subtracted from an IPv6 address. |
| /// |
| /// Subtracting an IP address from another IP address of the same type |
| /// returns an integer of the appropriate width. A `u32` for IPv4 and a |
| /// `u128` for IPv6. Subtracting IP addresses is useful for getting |
| /// the range between two IP addresses. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use std::net::{Ipv4Addr, Ipv6Addr}; |
| /// use ipnet::IpSub; |
| /// |
| /// let min: Ipv4Addr = "0.0.0.0".parse().unwrap(); |
| /// let ip1: Ipv4Addr = "192.168.1.5".parse().unwrap(); |
| /// let ip2: Ipv4Addr = "192.168.1.100".parse().unwrap(); |
| /// |
| /// assert_eq!(min.saturating_sub(ip1), 0); |
| /// assert_eq!(ip2.saturating_sub(ip1), 95); |
| /// assert_eq!(min.saturating_sub(5), min); |
| /// assert_eq!(ip2.saturating_sub(95), ip1); |
| /// |
| /// let min: Ipv6Addr = "::".parse().unwrap(); |
| /// let ip1: Ipv6Addr = "fd00::5".parse().unwrap(); |
| /// let ip2: Ipv6Addr = "fd00::64".parse().unwrap(); |
| /// |
| /// assert_eq!(min.saturating_sub(ip1), 0); |
| /// assert_eq!(ip2.saturating_sub(ip1), 95); |
| /// assert_eq!(min.saturating_sub(5u128), min); |
| /// assert_eq!(ip2.saturating_sub(95u128), ip1); |
| /// ``` |
| pub trait IpSub<RHS = Self> { |
| type Output; |
| fn saturating_sub(self, rhs: RHS) -> Self::Output; |
| } |
| |
| /// Provides a `bitand()` method for `Ipv4Addr` and `Ipv6Addr`. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use std::net::{Ipv4Addr, Ipv6Addr}; |
| /// use ipnet::IpBitAnd; |
| /// |
| /// let ip: Ipv4Addr = "192.168.1.1".parse().unwrap(); |
| /// let mask: Ipv4Addr = "255.255.0.0".parse().unwrap(); |
| /// let res: Ipv4Addr = "192.168.0.0".parse().unwrap(); |
| /// |
| /// assert_eq!(ip.bitand(mask), res); |
| /// assert_eq!(ip.bitand(0xffff0000), res); |
| /// |
| /// let ip: Ipv6Addr = "fd00:1234::1".parse().unwrap(); |
| /// let mask: Ipv6Addr = "ffff::".parse().unwrap(); |
| /// let res: Ipv6Addr = "fd00::".parse().unwrap(); |
| /// |
| /// assert_eq!(ip.bitand(mask), res); |
| /// assert_eq!(ip.bitand(0xffff_0000_0000_0000_0000_0000_0000_0000u128), res); |
| /// ``` |
| pub trait IpBitAnd<RHS = Self> { |
| type Output; |
| fn bitand(self, rhs: RHS) -> Self::Output; |
| } |
| |
| /// Provides a `bitor()` method for `Ipv4Addr` and `Ipv6Addr`. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use std::net::{Ipv4Addr, Ipv6Addr}; |
| /// use ipnet::IpBitOr; |
| /// |
| /// let ip: Ipv4Addr = "10.1.1.1".parse().unwrap(); |
| /// let mask: Ipv4Addr = "0.0.0.255".parse().unwrap(); |
| /// let res: Ipv4Addr = "10.1.1.255".parse().unwrap(); |
| /// |
| /// assert_eq!(ip.bitor(mask), res); |
| /// assert_eq!(ip.bitor(0x000000ff), res); |
| /// |
| /// let ip: Ipv6Addr = "fd00::1".parse().unwrap(); |
| /// let mask: Ipv6Addr = "::ffff:ffff".parse().unwrap(); |
| /// let res: Ipv6Addr = "fd00::ffff:ffff".parse().unwrap(); |
| /// |
| /// assert_eq!(ip.bitor(mask), res); |
| /// assert_eq!(ip.bitor(u128::from(0xffffffffu32)), res); |
| /// ``` |
| pub trait IpBitOr<RHS = Self> { |
| type Output; |
| fn bitor(self, rhs: RHS) -> Self::Output; |
| } |
| |
| macro_rules! ip_add_impl { |
| ($lhs:ty, $rhs:ty, $output:ty, $inner:ty) => ( |
| impl IpAdd<$rhs> for $lhs { |
| type Output = $output; |
| |
| fn saturating_add(self, rhs: $rhs) -> $output { |
| let lhs: $inner = self.into(); |
| let rhs: $inner = rhs.into(); |
| (lhs.saturating_add(rhs.into())).into() |
| } |
| } |
| ) |
| } |
| |
| macro_rules! ip_sub_impl { |
| ($lhs:ty, $rhs:ty, $output:ty, $inner:ty) => ( |
| impl IpSub<$rhs> for $lhs { |
| type Output = $output; |
| |
| fn saturating_sub(self, rhs: $rhs) -> $output { |
| let lhs: $inner = self.into(); |
| let rhs: $inner = rhs.into(); |
| (lhs.saturating_sub(rhs.into())).into() |
| } |
| } |
| ) |
| } |
| |
| ip_add_impl!(Ipv4Addr, u32, Ipv4Addr, u32); |
| ip_add_impl!(Ipv6Addr, u128, Ipv6Addr, u128); |
| |
| ip_sub_impl!(Ipv4Addr, Ipv4Addr, u32, u32); |
| ip_sub_impl!(Ipv4Addr, u32, Ipv4Addr, u32); |
| ip_sub_impl!(Ipv6Addr, Ipv6Addr, u128, u128); |
| ip_sub_impl!(Ipv6Addr, u128, Ipv6Addr, u128); |
| |
| macro_rules! ip_bitops_impl { |
| ($(($lhs:ty, $rhs:ty, $t:ty),)*) => { |
| $( |
| impl IpBitAnd<$rhs> for $lhs { |
| type Output = $lhs; |
| |
| fn bitand(self, rhs: $rhs) -> $lhs { |
| let lhs: $t = self.into(); |
| let rhs: $t = rhs.into(); |
| (lhs & rhs).into() |
| } |
| } |
| |
| impl IpBitOr<$rhs> for $lhs { |
| type Output = $lhs; |
| |
| fn bitor(self, rhs: $rhs) -> $lhs { |
| let lhs: $t = self.into(); |
| let rhs: $t = rhs.into(); |
| (lhs | rhs).into() |
| } |
| } |
| )* |
| } |
| } |
| |
| ip_bitops_impl! { |
| (Ipv4Addr, Ipv4Addr, u32), |
| (Ipv4Addr, u32, u32), |
| (Ipv6Addr, Ipv6Addr, u128), |
| (Ipv6Addr, u128, u128), |
| } |
| |
| // A barebones copy of the current unstable Step trait used by the |
| // IpAddrRange, Ipv4AddrRange, and Ipv6AddrRange types below, and the |
| // Subnets types in ipnet. |
| pub trait IpStep { |
| fn replace_one(&mut self) -> Self; |
| fn replace_zero(&mut self) -> Self; |
| fn add_one(&self) -> Self; |
| fn sub_one(&self) -> Self; |
| } |
| |
| impl IpStep for Ipv4Addr { |
| fn replace_one(&mut self) -> Self { |
| mem::replace(self, Ipv4Addr::new(0, 0, 0, 1)) |
| } |
| fn replace_zero(&mut self) -> Self { |
| mem::replace(self, Ipv4Addr::new(0, 0, 0, 0)) |
| } |
| fn add_one(&self) -> Self { |
| self.saturating_add(1) |
| } |
| fn sub_one(&self) -> Self { |
| self.saturating_sub(1) |
| } |
| } |
| |
| impl IpStep for Ipv6Addr { |
| fn replace_one(&mut self) -> Self { |
| mem::replace(self, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)) |
| } |
| fn replace_zero(&mut self) -> Self { |
| mem::replace(self, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)) |
| } |
| fn add_one(&self) -> Self { |
| self.saturating_add(1) |
| } |
| fn sub_one(&self) -> Self { |
| self.saturating_sub(1) |
| } |
| } |
| |
| /// An `Iterator` over a range of IP addresses, either IPv4 or IPv6. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use std::net::IpAddr; |
| /// use ipnet::{IpAddrRange, Ipv4AddrRange, Ipv6AddrRange}; |
| /// |
| /// let hosts = IpAddrRange::from(Ipv4AddrRange::new( |
| /// "10.0.0.0".parse().unwrap(), |
| /// "10.0.0.3".parse().unwrap(), |
| /// )); |
| /// |
| /// assert_eq!(hosts.collect::<Vec<IpAddr>>(), vec![ |
| /// "10.0.0.0".parse::<IpAddr>().unwrap(), |
| /// "10.0.0.1".parse().unwrap(), |
| /// "10.0.0.2".parse().unwrap(), |
| /// "10.0.0.3".parse().unwrap(), |
| /// ]); |
| /// |
| /// let hosts = IpAddrRange::from(Ipv6AddrRange::new( |
| /// "fd00::".parse().unwrap(), |
| /// "fd00::3".parse().unwrap(), |
| /// )); |
| /// |
| /// assert_eq!(hosts.collect::<Vec<IpAddr>>(), vec![ |
| /// "fd00::0".parse::<IpAddr>().unwrap(), |
| /// "fd00::1".parse().unwrap(), |
| /// "fd00::2".parse().unwrap(), |
| /// "fd00::3".parse().unwrap(), |
| /// ]); |
| /// ``` |
| #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] |
| pub enum IpAddrRange { |
| V4(Ipv4AddrRange), |
| V6(Ipv6AddrRange), |
| } |
| |
| /// An `Iterator` over a range of IPv4 addresses. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use std::net::Ipv4Addr; |
| /// use ipnet::Ipv4AddrRange; |
| /// |
| /// let hosts = Ipv4AddrRange::new( |
| /// "10.0.0.0".parse().unwrap(), |
| /// "10.0.0.3".parse().unwrap(), |
| /// ); |
| /// |
| /// assert_eq!(hosts.collect::<Vec<Ipv4Addr>>(), vec![ |
| /// "10.0.0.0".parse::<Ipv4Addr>().unwrap(), |
| /// "10.0.0.1".parse().unwrap(), |
| /// "10.0.0.2".parse().unwrap(), |
| /// "10.0.0.3".parse().unwrap(), |
| /// ]); |
| /// ``` |
| #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] |
| pub struct Ipv4AddrRange { |
| start: Ipv4Addr, |
| end: Ipv4Addr, |
| } |
| |
| /// An `Iterator` over a range of IPv6 addresses. |
| /// |
| /// # Examples |
| /// |
| /// ``` |
| /// use std::net::Ipv6Addr; |
| /// use ipnet::Ipv6AddrRange; |
| /// |
| /// let hosts = Ipv6AddrRange::new( |
| /// "fd00::".parse().unwrap(), |
| /// "fd00::3".parse().unwrap(), |
| /// ); |
| /// |
| /// assert_eq!(hosts.collect::<Vec<Ipv6Addr>>(), vec![ |
| /// "fd00::".parse::<Ipv6Addr>().unwrap(), |
| /// "fd00::1".parse().unwrap(), |
| /// "fd00::2".parse().unwrap(), |
| /// "fd00::3".parse().unwrap(), |
| /// ]); |
| /// ``` |
| #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] |
| pub struct Ipv6AddrRange { |
| start: Ipv6Addr, |
| end: Ipv6Addr, |
| } |
| |
| impl From<Ipv4AddrRange> for IpAddrRange { |
| fn from(i: Ipv4AddrRange) -> IpAddrRange { |
| IpAddrRange::V4(i) |
| } |
| } |
| |
| impl From<Ipv6AddrRange> for IpAddrRange { |
| fn from(i: Ipv6AddrRange) -> IpAddrRange { |
| IpAddrRange::V6(i) |
| } |
| } |
| |
| impl Ipv4AddrRange { |
| pub fn new(start: Ipv4Addr, end: Ipv4Addr) -> Self { |
| Ipv4AddrRange { |
| start: start, |
| end: end, |
| } |
| } |
| /// Counts the number of Ipv4Addr in this range. |
| /// This method will never overflow or panic. |
| fn count_u64(&self) -> u64 { |
| match self.start.partial_cmp(&self.end) { |
| Some(Less) => { |
| let count: u32 = self.end.saturating_sub(self.start); |
| let count = count as u64 + 1; // Never overflows |
| count |
| }, |
| Some(Equal) => 1, |
| _ => 0, |
| } |
| } |
| } |
| |
| impl Ipv6AddrRange { |
| pub fn new(start: Ipv6Addr, end: Ipv6Addr) -> Self { |
| Ipv6AddrRange { |
| start: start, |
| end: end, |
| } |
| } |
| /// Counts the number of Ipv6Addr in this range. |
| /// This method may overflow or panic if start |
| /// is 0 and end is u128::MAX |
| fn count_u128(&self) -> u128 { |
| match self.start.partial_cmp(&self.end) { |
| Some(Less) => { |
| let count = self.end.saturating_sub(self.start); |
| // May overflow or panic |
| count + 1 |
| }, |
| Some(Equal) => 1, |
| _ => 0, |
| } |
| } |
| /// True only if count_u128 does not overflow |
| fn can_count_u128(&self) -> bool { |
| self.start != Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0) |
| || self.end != Ipv6Addr::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff) |
| } |
| } |
| |
| impl Iterator for IpAddrRange { |
| type Item = IpAddr; |
| |
| fn next(&mut self) -> Option<Self::Item> { |
| match *self { |
| IpAddrRange::V4(ref mut a) => a.next().map(IpAddr::V4), |
| IpAddrRange::V6(ref mut a) => a.next().map(IpAddr::V6), |
| } |
| } |
| |
| fn count(self) -> usize { |
| match self { |
| IpAddrRange::V4(a) => a.count(), |
| IpAddrRange::V6(a) => a.count(), |
| } |
| } |
| |
| fn last(self) -> Option<Self::Item> { |
| match self { |
| IpAddrRange::V4(a) => a.last().map(IpAddr::V4), |
| IpAddrRange::V6(a) => a.last().map(IpAddr::V6), |
| } |
| } |
| |
| fn max(self) -> Option<Self::Item> { |
| match self { |
| IpAddrRange::V4(a) => Iterator::max(a).map(IpAddr::V4), |
| IpAddrRange::V6(a) => Iterator::max(a).map(IpAddr::V6), |
| } |
| } |
| |
| fn min(self) -> Option<Self::Item> { |
| match self { |
| IpAddrRange::V4(a) => Iterator::min(a).map(IpAddr::V4), |
| IpAddrRange::V6(a) => Iterator::min(a).map(IpAddr::V6), |
| } |
| } |
| |
| fn nth(&mut self, n: usize) -> Option<Self::Item> { |
| match *self { |
| IpAddrRange::V4(ref mut a) => a.nth(n).map(IpAddr::V4), |
| IpAddrRange::V6(ref mut a) => a.nth(n).map(IpAddr::V6), |
| } |
| } |
| |
| fn size_hint(&self) -> (usize, Option<usize>) { |
| match *self { |
| IpAddrRange::V4(ref a) => a.size_hint(), |
| IpAddrRange::V6(ref a) => a.size_hint(), |
| } |
| } |
| } |
| |
| impl Iterator for Ipv4AddrRange { |
| type Item = Ipv4Addr; |
| |
| fn next(&mut self) -> Option<Self::Item> { |
| match self.start.partial_cmp(&self.end) { |
| Some(Less) => { |
| let next = self.start.add_one(); |
| Some(mem::replace(&mut self.start, next)) |
| }, |
| Some(Equal) => { |
| self.end.replace_zero(); |
| Some(self.start.replace_one()) |
| }, |
| _ => None, |
| } |
| } |
| |
| #[allow(const_err)] |
| #[allow(arithmetic_overflow)] |
| fn count(self) -> usize { |
| match self.start.partial_cmp(&self.end) { |
| Some(Less) => { |
| // Adding one here might overflow u32. |
| // Instead, wait until after converted to usize |
| let count: u32 = self.end.saturating_sub(self.start); |
| |
| // usize might only be 16 bits, |
| // so need to explicitly check for overflow. |
| // 'usize::MAX as u32' is okay here - if usize is 64 bits, |
| // value truncates to u32::MAX |
| if count <= std::usize::MAX as u32 { |
| count as usize + 1 |
| // count overflows usize |
| } else { |
| // emulate standard overflow/panic behavior |
| std::usize::MAX + 2 + count as usize |
| } |
| }, |
| Some(Equal) => 1, |
| _ => 0 |
| } |
| } |
| |
| fn last(self) -> Option<Self::Item> { |
| match self.start.partial_cmp(&self.end) { |
| Some(Less) | Some(Equal) => Some(self.end), |
| _ => None, |
| } |
| } |
| |
| fn max(self) -> Option<Self::Item> { |
| self.last() |
| } |
| |
| fn min(self) -> Option<Self::Item> { |
| match self.start.partial_cmp(&self.end) { |
| Some(Less) | Some(Equal) => Some(self.start), |
| _ => None |
| } |
| } |
| |
| fn nth(&mut self, n: usize) -> Option<Self::Item> { |
| let n = n as u64; |
| let count = self.count_u64(); |
| if n >= count { |
| self.end.replace_zero(); |
| self.start.replace_one(); |
| None |
| } else if n == count - 1 { |
| self.start.replace_one(); |
| Some(self.end.replace_zero()) |
| } else { |
| let nth = self.start.saturating_add(n as u32); |
| self.start = nth.add_one(); |
| Some(nth) |
| } |
| } |
| |
| fn size_hint(&self) -> (usize, Option<usize>) { |
| let count = self.count_u64(); |
| if count > std::usize::MAX as u64 { |
| (std::usize::MAX, None) |
| } else { |
| let count = count as usize; |
| (count, Some(count)) |
| } |
| } |
| } |
| |
| impl Iterator for Ipv6AddrRange { |
| type Item = Ipv6Addr; |
| |
| fn next(&mut self) -> Option<Self::Item> { |
| match self.start.partial_cmp(&self.end) { |
| Some(Less) => { |
| let next = self.start.add_one(); |
| Some(mem::replace(&mut self.start, next)) |
| }, |
| Some(Equal) => { |
| self.end.replace_zero(); |
| Some(self.start.replace_one()) |
| }, |
| _ => None, |
| } |
| } |
| |
| #[allow(const_err)] |
| #[allow(arithmetic_overflow)] |
| fn count(self) -> usize { |
| let count = self.count_u128(); |
| // count fits in usize |
| if count <= std::usize::MAX as u128 { |
| count as usize |
| // count does not fit in usize |
| } else { |
| // emulate standard overflow/panic behavior |
| std::usize::MAX + 1 + count as usize |
| } |
| } |
| |
| fn last(self) -> Option<Self::Item> { |
| match self.start.partial_cmp(&self.end) { |
| Some(Less) | Some(Equal) => Some(self.end), |
| _ => None, |
| } |
| } |
| |
| fn max(self) -> Option<Self::Item> { |
| self.last() |
| } |
| |
| fn min(self) -> Option<Self::Item> { |
| match self.start.partial_cmp(&self.end) { |
| Some(Less) | Some(Equal) => Some(self.start), |
| _ => None |
| } |
| } |
| |
| fn nth(&mut self, n: usize) -> Option<Self::Item> { |
| let n = n as u128; |
| if self.can_count_u128() { |
| let count = self.count_u128(); |
| if n >= count { |
| self.end.replace_zero(); |
| self.start.replace_one(); |
| None |
| } else if n == count - 1 { |
| self.start.replace_one(); |
| Some(self.end.replace_zero()) |
| } else { |
| let nth = self.start.saturating_add(n); |
| self.start = nth.add_one(); |
| Some(nth) |
| } |
| // count overflows u128; n is 64-bits at most. |
| // therefore, n can never exceed count |
| } else { |
| let nth = self.start.saturating_add(n); |
| self.start = nth.add_one(); |
| Some(nth) |
| } |
| } |
| |
| fn size_hint(&self) -> (usize, Option<usize>) { |
| if self.can_count_u128() { |
| let count = self.count_u128(); |
| if count > std::usize::MAX as u128 { |
| (std::usize::MAX, None) |
| } else { |
| let count = count as usize; |
| (count, Some(count)) |
| } |
| } else { |
| (std::usize::MAX, None) |
| } |
| } |
| } |
| |
| impl DoubleEndedIterator for IpAddrRange { |
| fn next_back(&mut self) -> Option<Self::Item> { |
| match *self { |
| IpAddrRange::V4(ref mut a) => a.next_back().map(IpAddr::V4), |
| IpAddrRange::V6(ref mut a) => a.next_back().map(IpAddr::V6), |
| } |
| } |
| fn nth_back(&mut self, n: usize) -> Option<Self::Item> { |
| match *self { |
| IpAddrRange::V4(ref mut a) => a.nth_back(n).map(IpAddr::V4), |
| IpAddrRange::V6(ref mut a) => a.nth_back(n).map(IpAddr::V6), |
| } |
| } |
| } |
| |
| impl DoubleEndedIterator for Ipv4AddrRange { |
| fn next_back(&mut self) -> Option<Self::Item> { |
| match self.start.partial_cmp(&self.end) { |
| Some(Less) => { |
| let next_back = self.end.sub_one(); |
| Some(mem::replace(&mut self.end, next_back)) |
| }, |
| Some(Equal) => { |
| self.end.replace_zero(); |
| Some(self.start.replace_one()) |
| }, |
| _ => None |
| } |
| } |
| fn nth_back(&mut self, n: usize) -> Option<Self::Item> { |
| let n = n as u64; |
| let count = self.count_u64(); |
| if n >= count { |
| self.end.replace_zero(); |
| self.start.replace_one(); |
| None |
| } else if n == count - 1 { |
| self.end.replace_zero(); |
| Some(self.start.replace_one()) |
| } else { |
| let nth_back = self.end.saturating_sub(n as u32); |
| self.end = nth_back.sub_one(); |
| Some(nth_back) |
| } |
| } |
| } |
| |
| impl DoubleEndedIterator for Ipv6AddrRange { |
| fn next_back(&mut self) -> Option<Self::Item> { |
| match self.start.partial_cmp(&self.end) { |
| Some(Less) => { |
| let next_back = self.end.sub_one(); |
| Some(mem::replace(&mut self.end, next_back)) |
| }, |
| Some(Equal) => { |
| self.end.replace_zero(); |
| Some(self.start.replace_one()) |
| }, |
| _ => None |
| } |
| } |
| fn nth_back(&mut self, n: usize) -> Option<Self::Item> { |
| let n = n as u128; |
| if self.can_count_u128() { |
| let count = self.count_u128(); |
| if n >= count { |
| self.end.replace_zero(); |
| self.start.replace_one(); |
| None |
| } |
| else if n == count - 1 { |
| self.end.replace_zero(); |
| Some(self.start.replace_one()) |
| } else { |
| let nth_back = self.end.saturating_sub(n); |
| self.end = nth_back.sub_one(); |
| Some(nth_back) |
| } |
| // count overflows u128; n is 64-bits at most. |
| // therefore, n can never exceed count |
| } else { |
| let nth_back = self.end.saturating_sub(n); |
| self.end = nth_back.sub_one(); |
| Some(nth_back) |
| } |
| } |
| } |
| |
| impl FusedIterator for IpAddrRange {} |
| impl FusedIterator for Ipv4AddrRange {} |
| impl FusedIterator for Ipv6AddrRange {} |
| |
| #[cfg(test)] |
| mod tests { |
| use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; |
| use std::str::FromStr; |
| use super::*; |
| |
| #[test] |
| fn test_ipaddrrange() { |
| // Next, Next-Back |
| let i = Ipv4AddrRange::new( |
| Ipv4Addr::from_str("10.0.0.0").unwrap(), |
| Ipv4Addr::from_str("10.0.0.3").unwrap() |
| ); |
| |
| assert_eq!(i.collect::<Vec<Ipv4Addr>>(), vec![ |
| Ipv4Addr::from_str("10.0.0.0").unwrap(), |
| Ipv4Addr::from_str("10.0.0.1").unwrap(), |
| Ipv4Addr::from_str("10.0.0.2").unwrap(), |
| Ipv4Addr::from_str("10.0.0.3").unwrap(), |
| ]); |
| |
| let mut v = i.collect::<Vec<_>>(); |
| v.reverse(); |
| assert_eq!(v, i.rev().collect::<Vec<_>>()); |
| |
| let i = Ipv4AddrRange::new( |
| Ipv4Addr::from_str("255.255.255.254").unwrap(), |
| Ipv4Addr::from_str("255.255.255.255").unwrap() |
| ); |
| |
| assert_eq!(i.collect::<Vec<Ipv4Addr>>(), vec![ |
| Ipv4Addr::from_str("255.255.255.254").unwrap(), |
| Ipv4Addr::from_str("255.255.255.255").unwrap(), |
| ]); |
| |
| let i = Ipv6AddrRange::new( |
| Ipv6Addr::from_str("fd00::").unwrap(), |
| Ipv6Addr::from_str("fd00::3").unwrap(), |
| ); |
| |
| assert_eq!(i.collect::<Vec<Ipv6Addr>>(), vec![ |
| Ipv6Addr::from_str("fd00::").unwrap(), |
| Ipv6Addr::from_str("fd00::1").unwrap(), |
| Ipv6Addr::from_str("fd00::2").unwrap(), |
| Ipv6Addr::from_str("fd00::3").unwrap(), |
| ]); |
| |
| let mut v = i.collect::<Vec<_>>(); |
| v.reverse(); |
| assert_eq!(v, i.rev().collect::<Vec<_>>()); |
| |
| let i = Ipv6AddrRange::new( |
| Ipv6Addr::from_str("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe").unwrap(), |
| Ipv6Addr::from_str("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff").unwrap(), |
| ); |
| |
| assert_eq!(i.collect::<Vec<Ipv6Addr>>(), vec![ |
| Ipv6Addr::from_str("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe").unwrap(), |
| Ipv6Addr::from_str("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff").unwrap(), |
| ]); |
| |
| let i = IpAddrRange::from(Ipv4AddrRange::new( |
| Ipv4Addr::from_str("10.0.0.0").unwrap(), |
| Ipv4Addr::from_str("10.0.0.3").unwrap(), |
| )); |
| |
| assert_eq!(i.collect::<Vec<IpAddr>>(), vec![ |
| IpAddr::from_str("10.0.0.0").unwrap(), |
| IpAddr::from_str("10.0.0.1").unwrap(), |
| IpAddr::from_str("10.0.0.2").unwrap(), |
| IpAddr::from_str("10.0.0.3").unwrap(), |
| ]); |
| |
| let mut v = i.collect::<Vec<_>>(); |
| v.reverse(); |
| assert_eq!(v, i.rev().collect::<Vec<_>>()); |
| |
| let i = IpAddrRange::from(Ipv4AddrRange::new( |
| Ipv4Addr::from_str("255.255.255.254").unwrap(), |
| Ipv4Addr::from_str("255.255.255.255").unwrap() |
| )); |
| |
| assert_eq!(i.collect::<Vec<IpAddr>>(), vec![ |
| IpAddr::from_str("255.255.255.254").unwrap(), |
| IpAddr::from_str("255.255.255.255").unwrap(), |
| ]); |
| |
| let i = IpAddrRange::from(Ipv6AddrRange::new( |
| Ipv6Addr::from_str("fd00::").unwrap(), |
| Ipv6Addr::from_str("fd00::3").unwrap(), |
| )); |
| |
| assert_eq!(i.collect::<Vec<IpAddr>>(), vec![ |
| IpAddr::from_str("fd00::").unwrap(), |
| IpAddr::from_str("fd00::1").unwrap(), |
| IpAddr::from_str("fd00::2").unwrap(), |
| IpAddr::from_str("fd00::3").unwrap(), |
| ]); |
| |
| let mut v = i.collect::<Vec<_>>(); |
| v.reverse(); |
| assert_eq!(v, i.rev().collect::<Vec<_>>()); |
| |
| let i = IpAddrRange::from(Ipv6AddrRange::new( |
| Ipv6Addr::from_str("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe").unwrap(), |
| Ipv6Addr::from_str("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff").unwrap(), |
| )); |
| |
| assert_eq!(i.collect::<Vec<IpAddr>>(), vec![ |
| IpAddr::from_str("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe").unwrap(), |
| IpAddr::from_str("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff").unwrap(), |
| ]); |
| |
| // #11 (infinite iterator when start and stop are 0) |
| let zero4 = Ipv4Addr::from_str("0.0.0.0").unwrap(); |
| let zero6 = Ipv6Addr::from_str("::").unwrap(); |
| |
| let mut i = Ipv4AddrRange::new(zero4, zero4); |
| assert_eq!(Some(zero4), i.next()); |
| assert_eq!(None, i.next()); |
| |
| let mut i = Ipv6AddrRange::new(zero6, zero6); |
| assert_eq!(Some(zero6), i.next()); |
| assert_eq!(None, i.next()); |
| |
| // Count |
| let i = Ipv4AddrRange::new( |
| Ipv4Addr::from_str("10.0.0.0").unwrap(), |
| Ipv4Addr::from_str("10.0.0.3").unwrap() |
| ); |
| assert_eq!(i.count(), 4); |
| |
| let i = Ipv6AddrRange::new( |
| Ipv6Addr::from_str("fd00::").unwrap(), |
| Ipv6Addr::from_str("fd00::3").unwrap(), |
| ); |
| assert_eq!(i.count(), 4); |
| |
| // Size Hint |
| let i = Ipv4AddrRange::new( |
| Ipv4Addr::from_str("10.0.0.0").unwrap(), |
| Ipv4Addr::from_str("10.0.0.3").unwrap() |
| ); |
| assert_eq!(i.size_hint(), (4, Some(4))); |
| |
| let i = Ipv6AddrRange::new( |
| Ipv6Addr::from_str("fd00::").unwrap(), |
| Ipv6Addr::from_str("fd00::3").unwrap(), |
| ); |
| assert_eq!(i.size_hint(), (4, Some(4))); |
| |
| // Size Hint: a range where size clearly overflows usize |
| let i = Ipv6AddrRange::new( |
| Ipv6Addr::from_str("::").unwrap(), |
| Ipv6Addr::from_str("8000::").unwrap(), |
| ); |
| assert_eq!(i.size_hint(), (std::usize::MAX, None)); |
| |
| // Min, Max, Last |
| let i = Ipv4AddrRange::new( |
| Ipv4Addr::from_str("10.0.0.0").unwrap(), |
| Ipv4Addr::from_str("10.0.0.3").unwrap() |
| ); |
| assert_eq!(Iterator::min(i), Some(Ipv4Addr::from_str("10.0.0.0").unwrap())); |
| assert_eq!(Iterator::max(i), Some(Ipv4Addr::from_str("10.0.0.3").unwrap())); |
| assert_eq!(i.last(), Some(Ipv4Addr::from_str("10.0.0.3").unwrap())); |
| |
| let i = Ipv6AddrRange::new( |
| Ipv6Addr::from_str("fd00::").unwrap(), |
| Ipv6Addr::from_str("fd00::3").unwrap(), |
| ); |
| assert_eq!(Iterator::min(i), Some(Ipv6Addr::from_str("fd00::").unwrap())); |
| assert_eq!(Iterator::max(i), Some(Ipv6Addr::from_str("fd00::3").unwrap())); |
| assert_eq!(i.last(), Some(Ipv6Addr::from_str("fd00::3").unwrap())); |
| |
| // Nth |
| let i = Ipv4AddrRange::new( |
| Ipv4Addr::from_str("10.0.0.0").unwrap(), |
| Ipv4Addr::from_str("10.0.0.3").unwrap() |
| ); |
| assert_eq!(i.clone().nth(0), Some(Ipv4Addr::from_str("10.0.0.0").unwrap())); |
| assert_eq!(i.clone().nth(3), Some(Ipv4Addr::from_str("10.0.0.3").unwrap())); |
| assert_eq!(i.clone().nth(4), None); |
| assert_eq!(i.clone().nth(99), None); |
| let mut i2 = i.clone(); |
| assert_eq!(i2.nth(1), Some(Ipv4Addr::from_str("10.0.0.1").unwrap())); |
| assert_eq!(i2.nth(1), Some(Ipv4Addr::from_str("10.0.0.3").unwrap())); |
| assert_eq!(i2.nth(0), None); |
| let mut i3 = i.clone(); |
| assert_eq!(i3.nth(99), None); |
| assert_eq!(i3.next(), None); |
| |
| let i = Ipv6AddrRange::new( |
| Ipv6Addr::from_str("fd00::").unwrap(), |
| Ipv6Addr::from_str("fd00::3").unwrap(), |
| ); |
| assert_eq!(i.clone().nth(0), Some(Ipv6Addr::from_str("fd00::").unwrap())); |
| assert_eq!(i.clone().nth(3), Some(Ipv6Addr::from_str("fd00::3").unwrap())); |
| assert_eq!(i.clone().nth(4), None); |
| assert_eq!(i.clone().nth(99), None); |
| let mut i2 = i.clone(); |
| assert_eq!(i2.nth(1), Some(Ipv6Addr::from_str("fd00::1").unwrap())); |
| assert_eq!(i2.nth(1), Some(Ipv6Addr::from_str("fd00::3").unwrap())); |
| assert_eq!(i2.nth(0), None); |
| let mut i3 = i.clone(); |
| assert_eq!(i3.nth(99), None); |
| assert_eq!(i3.next(), None); |
| |
| // Nth Back |
| let i = Ipv4AddrRange::new( |
| Ipv4Addr::from_str("10.0.0.0").unwrap(), |
| Ipv4Addr::from_str("10.0.0.3").unwrap() |
| ); |
| assert_eq!(i.clone().nth_back(0), Some(Ipv4Addr::from_str("10.0.0.3").unwrap())); |
| assert_eq!(i.clone().nth_back(3), Some(Ipv4Addr::from_str("10.0.0.0").unwrap())); |
| assert_eq!(i.clone().nth_back(4), None); |
| assert_eq!(i.clone().nth_back(99), None); |
| let mut i2 = i.clone(); |
| assert_eq!(i2.nth_back(1), Some(Ipv4Addr::from_str("10.0.0.2").unwrap())); |
| assert_eq!(i2.nth_back(1), Some(Ipv4Addr::from_str("10.0.0.0").unwrap())); |
| assert_eq!(i2.nth_back(0), None); |
| let mut i3 = i.clone(); |
| assert_eq!(i3.nth_back(99), None); |
| assert_eq!(i3.next(), None); |
| |
| let i = Ipv6AddrRange::new( |
| Ipv6Addr::from_str("fd00::").unwrap(), |
| Ipv6Addr::from_str("fd00::3").unwrap(), |
| ); |
| assert_eq!(i.clone().nth_back(0), Some(Ipv6Addr::from_str("fd00::3").unwrap())); |
| assert_eq!(i.clone().nth_back(3), Some(Ipv6Addr::from_str("fd00::").unwrap())); |
| assert_eq!(i.clone().nth_back(4), None); |
| assert_eq!(i.clone().nth_back(99), None); |
| let mut i2 = i.clone(); |
| assert_eq!(i2.nth_back(1), Some(Ipv6Addr::from_str("fd00::2").unwrap())); |
| assert_eq!(i2.nth_back(1), Some(Ipv6Addr::from_str("fd00::").unwrap())); |
| assert_eq!(i2.nth_back(0), None); |
| let mut i3 = i.clone(); |
| assert_eq!(i3.nth_back(99), None); |
| assert_eq!(i3.next(), None); |
| } |
| } |