967 lines
30 KiB
Rust
967 lines
30 KiB
Rust
//! 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);
|
|
}
|
|
}
|