use std::cmp::Ordering::{Less, Equal};
use std::iter::{FusedIterator, DoubleEndedIterator};
use std::mem;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
pub trait IpAdd<RHS = Self> {
    type Output;
    fn saturating_add(self, rhs: RHS) -> Self::Output;
}
pub trait IpSub<RHS = Self> {
    type Output;
    fn saturating_sub(self, rhs: RHS) -> Self::Output;
}
pub trait IpBitAnd<RHS = Self> {
    type Output;
    fn bitand(self, rhs: RHS) -> Self::Output;
}
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),
}
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)
    }
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum IpAddrRange {
    V4(Ipv4AddrRange),
    V6(Ipv6AddrRange),
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct Ipv4AddrRange {
    start: Ipv4Addr,
    end: Ipv4Addr,
}
#[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,
        }
    }
    
    
    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; 
                count
            },
            Some(Equal) => 1,
            _ => 0,
        }
    }
}
impl Ipv6AddrRange {
    pub fn new(start: Ipv6Addr, end: Ipv6Addr) -> Self {
        Ipv6AddrRange {
            start: start,
            end: end,
        }
    }
    
    
    
    fn count_u128(&self) -> u128 {
        match self.start.partial_cmp(&self.end) {
            Some(Less) => {
                let count = self.end.saturating_sub(self.start);
                
                count + 1
            },
            Some(Equal) => 1,
            _ => 0,
        }
    }
    
    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) => {
                
                
                let count: u32 = self.end.saturating_sub(self.start);
                
                
                
                
                if count <= std::usize::MAX as u32 {
                    count as usize + 1
                
                } else {
                    
                    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();
        
        if count <= std::usize::MAX as u128 {
            count as usize
        
        } else {
            
            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)
            }
        
        
        } 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)
            }
        
        
        } 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() {
        
        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(),
        ]);
        
        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());
        
        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);
        
        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)));
        
        let i = Ipv6AddrRange::new(
            Ipv6Addr::from_str("::").unwrap(),
            Ipv6Addr::from_str("8000::").unwrap(),
        );
        assert_eq!(i.size_hint(), (std::usize::MAX, None));
        
        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()));
        
        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);
        
        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);
    }
}