From 6f506ca7d12f7798eb4aa662b64c8b0497e8957b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BChler?= Date: Tue, 25 Jun 2024 14:47:51 +0200 Subject: [PATCH] expose some arithmetic methods on Inet types --- src/inet/combined.rs | 91 ++++++++++++++ src/inet/direct.rs | 157 +++++++++++++++++++++++++ src/inet/tests.rs | 71 ++++++++++- src/internal_traits.rs | 261 +++++++++++++++++++++++------------------ src/traits.rs | 17 +++ 5 files changed, 485 insertions(+), 112 deletions(-) diff --git a/src/inet/combined.rs b/src/inet/combined.rs index ba877c1..5b039c5 100644 --- a/src/inet/combined.rs +++ b/src/inet/combined.rs @@ -83,6 +83,61 @@ impl IpInet { } } + /// decrements host part (without changing the network part); + /// returns true on wrap around + pub fn decrement(&mut self) -> bool { + match self { + Self::V4(mut c) => c.decrement(), + Self::V6(mut c) => c.decrement(), + } + } + + /// Returns previous address in network or `None` if it was the first address in the network + pub const fn previous(self) -> Option { + match self { + Self::V4(c) => match c.previous() { + Some(c) => Some(Self::V4(c)), + None => None, + }, + Self::V6(c) => match c.previous() { + Some(c) => Some(Self::V6(c)), + None => None, + }, + } + } + + /// Find the nth host after the current one in the current network + /// + /// Returned boolean indicates whether an overflow occured. + pub const fn overflowing_add(self, step: u128) -> (Self, bool) { + match self { + Self::V4(c) => { + let (c, overflow) = c.overflowing_add(step); + (Self::V4(c), overflow) + }, + Self::V6(c) => { + let (c, overflow) = c.overflowing_add(step); + (Self::V6(c), overflow) + }, + } + } + + /// Find the nth host before the current one in the current network + /// + /// Returned boolean indicates whether an overflow occured. + pub const fn overflowing_sub(self, step: u128) -> (Self, bool) { + match self { + Self::V4(c) => { + let (c, overflow) = c.overflowing_sub(step); + (Self::V4(c), overflow) + }, + Self::V6(c) => { + let (c, overflow) = c.overflowing_sub(step); + (Self::V6(c), overflow) + }, + } + } + /// network (i.e. drops the host information) pub const fn network(&self) -> IpCidr { match self { @@ -203,6 +258,22 @@ impl Inet for IpInet { self.next() } + fn decrement(&mut self) -> bool { + self.decrement() + } + + fn previous(self) -> Option { + self.previous() + } + + fn overflowing_add(self, step: u128) -> (Self, bool) { + self.overflowing_add(step) + } + + fn overflowing_sub(self, step: u128) -> (Self, bool) { + self.overflowing_sub(step) + } + fn network(&self) -> IpCidr { self.network() } @@ -276,3 +347,23 @@ impl From for IpInet { Self::V6(c) } } + +impl core::ops::Add for IpInet { + type Output = IpInet; + + fn add(self, step: u128) -> Self::Output { + let (result, overflow) = self.overflowing_add(step); + debug_assert!(!overflow, "{} + {} overflow", self, step); + result + } +} + +impl core::ops::Sub for IpInet { + type Output = IpInet; + + fn sub(self, step: u128) -> Self::Output { + let (result, overflow) = self.overflowing_sub(step); + debug_assert!(!overflow, "{} - {} overflow", self, step); + result + } +} diff --git a/src/inet/direct.rs b/src/inet/direct.rs index d96d877..19e1906 100644 --- a/src/inet/direct.rs +++ b/src/inet/direct.rs @@ -126,6 +126,69 @@ macro_rules! impl_inet_for { } } + /// decrements host part (without changing the network part); + /// returns true on wrap around + pub fn decrement(&mut self) -> bool { + let (address, overflow) = <$addr as PrivUnspecAddress>::_Tools::_overflowing_prev( + self.address, + self.network_length, + ); + self.address = address; + overflow + } + + /// Returns previous address in network or `None` if it was the first address in the network + pub const fn previous(self) -> Option { + let (address, overflow) = <$addr as PrivUnspecAddress>::_Tools::_overflowing_prev( + self.address, + self.network_length, + ); + if overflow { + None + } else { + Some(Self { + address, + network_length: self.network_length, + }) + } + } + + /// Find the nth host after the current one in the current network + /// + /// Returned boolean indicates whether an overflow occured. + pub const fn overflowing_add(self, step: u128) -> (Self, bool) { + let (address, overflow) = <$addr as PrivUnspecAddress>::_Tools::_overflowing_inc( + self.address, + self.network_length, + step, + ); + ( + Self { + address, + network_length: self.network_length, + }, + overflow, + ) + } + + /// Find the nth host before the current one in the current network + /// + /// Returned boolean indicates whether an overflow occured. + pub const fn overflowing_sub(self, step: u128) -> (Self, bool) { + let (address, overflow) = <$addr as PrivUnspecAddress>::_Tools::_overflowing_dec( + self.address, + self.network_length, + step, + ); + ( + Self { + address, + network_length: self.network_length, + }, + overflow, + ) + } + /// network (i.e. drops the host information) pub const fn network(&self) -> $cidr { $cidr { @@ -226,6 +289,22 @@ macro_rules! impl_inet_for { self.next() } + fn decrement(&mut self) -> bool { + self.decrement() + } + + fn previous(self) -> Option { + self.previous() + } + + fn overflowing_add(self, step: u128) -> (Self, bool) { + self.overflowing_add(step) + } + + fn overflowing_sub(self, step: u128) -> (Self, bool) { + self.overflowing_sub(step) + } + fn network(&self) -> $cidr { self.network() } @@ -295,8 +374,86 @@ macro_rules! impl_inet_for { inet_from_str(s) } } + + impl core::ops::Add for $n { + type Output = $n; + + fn add(self, step: u128) -> Self::Output { + let (result, overflow) = self.overflowing_add(step); + debug_assert!(!overflow, "{} + {} overflow", self, step); + result + } + } + + impl core::ops::Sub for $n { + type Output = $n; + + fn sub(self, step: u128) -> Self::Output { + let (result, overflow) = self.overflowing_sub(step); + debug_assert!(!overflow, "{} - {} overflow", self, step); + result + } + } }; } impl_inet_for! {Ipv4Inet : cidr Ipv4Cidr : addr Ipv4Addr : pair Ipv4InetPair : family Family::Ipv4} impl_inet_for! {Ipv6Inet : cidr Ipv6Cidr : addr Ipv6Addr : pair Ipv6InetPair : family Family::Ipv6} + +impl Ipv4Inet { + /// Find the nth host after the current one in the current network (32-bit IPv4 variant) + /// + /// Returned boolean indicates whether an overflow occured. + pub const fn overflowing_add_u32(self, step: u32) -> (Self, bool) { + let (address, overflow) = ::_Tools::_overflowing_inc_u32( + self.address, + self.network_length, + step, + ); + ( + Self { + address, + network_length: self.network_length, + }, + overflow, + ) + } + + /// Find the nth host before the current one in the current network (32-bit IPv4 variant) + /// + /// Returned boolean indicates whether an overflow occured. + pub const fn overflowing_sub_u32(self, step: u32) -> (Self, bool) { + let (address, overflow) = ::_Tools::_overflowing_dec_u32( + self.address, + self.network_length, + step, + ); + ( + Self { + address, + network_length: self.network_length, + }, + overflow, + ) + } +} + +impl core::ops::Add for Ipv4Inet { + type Output = Ipv4Inet; + + fn add(self, step: u32) -> Self::Output { + let (result, overflow) = self.overflowing_add_u32(step); + debug_assert!(!overflow, "{} + {} overflow", self, step); + result + } +} + +impl core::ops::Sub for Ipv4Inet { + type Output = Ipv4Inet; + + fn sub(self, step: u32) -> Self::Output { + let (result, overflow) = self.overflowing_sub_u32(step); + debug_assert!(!overflow, "{} - {} overflow", self, step); + result + } +} diff --git a/src/inet/tests.rs b/src/inet/tests.rs index 159352a..c8cb44f 100644 --- a/src/inet/tests.rs +++ b/src/inet/tests.rs @@ -1,4 +1,7 @@ -use core::cmp::Ordering; +use core::{ + cmp::Ordering, + str::FromStr, +}; use std::net::{ IpAddr, Ipv4Addr, @@ -6,6 +9,8 @@ use std::net::{ }; use crate::{ + errors::NetworkParseError, + Inet, IpInet, Ipv4Inet, Ipv6Inet, @@ -963,3 +968,67 @@ fn order_v6() { fn order() { test_order(Ordering::Less, "192.0.2.0/24", "2001:DB8:1234:5678::/64"); } + +fn test_nth(a: &str, b: &str, step: u128, overflow: bool) +where + I: Inet + + FromStr + + core::ops::Add + + core::ops::Sub, +{ + let a = a.parse::().unwrap(); + let b = b.parse::().unwrap(); + + assert_eq!(a.overflowing_add(step), (b, overflow)); + assert_eq!(b.overflowing_sub(step), (a, overflow)); + + if !overflow { + // overflow would trigger debug asserts here + assert_eq!(a + step, b); + assert_eq!(b - step, a); + } +} + +#[test] +fn test_nth_v4() { + test_nth::("255.255.255.255/0", "0.0.0.0/0", 1, true); + test_nth::("255.255.255.255/0", "0.0.0.0/0", 1, true); + test_nth::("255.255.255.255/0", "127.0.0.1/0", 0x7f000002, true); + test_nth::("255.255.255.255/0", "127.0.0.1/0", 0x7f000002, true); + + test_nth::("192.0.2.23/24", "192.0.2.42/24", 19, false); + test_nth::("192.0.2.23/24", "192.0.2.42/24", 19, false); + test_nth::("192.0.2.42/24", "192.0.2.23/24", 237, true); + test_nth::("192.0.2.42/24", "192.0.2.23/24", 237, true); +} + +#[test] +fn test_nth_v6() { + test_nth::("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/0", "::/0", 1, true); + test_nth::("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/0", "::/0", 1, true); + + test_nth::( + "2001:DB8:1234:5678::23/64", + "2001:DB8:1234:5678::42/64", + 0x1f, + false, + ); + test_nth::( + "2001:DB8:1234:5678::23/64", + "2001:DB8:1234:5678::42/64", + 0x1f, + false, + ); + test_nth::( + "2001:DB8:1234:5678::42/64", + "2001:DB8:1234:5678::23/64", + (1 << 64) - 0x1f, + true, + ); + test_nth::( + "2001:DB8:1234:5678::42/64", + "2001:DB8:1234:5678::23/64", + (1 << 64) - 0x1f, + true, + ); +} diff --git a/src/internal_traits.rs b/src/internal_traits.rs index eef527a..58b5d26 100644 --- a/src/internal_traits.rs +++ b/src/internal_traits.rs @@ -57,18 +57,18 @@ impl Ipv4OverflowingOp { pub struct Ipv4AddrTools(()); impl Ipv4AddrTools { - pub const fn to_native(ip: Ipv4Addr) -> u32 { + pub(crate) const fn to_native(ip: Ipv4Addr) -> u32 { // const: u32::from u32::from_be_bytes(ip.octets()) } - pub const fn from_native(ip: u32) -> Ipv4Addr { + pub(crate) const fn from_native(ip: u32) -> Ipv4Addr { // const: Ipv4Addr::from let ip = ip.to_be_bytes(); Ipv4Addr::new(ip[0], ip[1], ip[2], ip[3]) } - pub const fn native_host_mask(prefix_len: u8) -> u32 { + pub(crate) const fn native_host_mask(prefix_len: u8) -> u32 { // const: unwrap_or(0) if let Some(mask) = (!0u32).checked_shr(prefix_len as u32) { mask @@ -77,61 +77,87 @@ impl Ipv4AddrTools { } } - pub const fn _has_zero_host_part(address: Ipv4Addr, prefix_len: u8) -> bool { + pub(crate) const fn _has_zero_host_part(address: Ipv4Addr, prefix_len: u8) -> bool { let host_mask: u32 = Self::native_host_mask(prefix_len); let addr_num = Self::to_native(address); (addr_num & host_mask) == 0 } - pub const fn _overflowing_next(address: Ipv4Addr, prefix_len: u8) -> (Ipv4Addr, bool) { + pub(crate) const fn _overflowing_next(address: Ipv4Addr, prefix_len: u8) -> (Ipv4Addr, bool) { let op = Ipv4OverflowingOp::new(address, prefix_len); op.handle_result(op.address.overflowing_add(1)) } - /* - pub const fn _overflowing_inc(address: Ipv4Addr, prefix_len: u8, step: u128) -> (Ipv4Addr, bool) { + pub(crate) const fn _overflowing_inc_u32( + address: Ipv4Addr, + prefix_len: u8, + step_u32: u32, + ) -> (Ipv4Addr, bool) { let op = Ipv4OverflowingOp::new(address, prefix_len); + let (res, overflow) = op.handle_result(op.address.overflowing_add(step_u32)); + (res, overflow) + } + + pub(crate) const fn _overflowing_inc( + address: Ipv4Addr, + prefix_len: u8, + step: u128, + ) -> (Ipv4Addr, bool) { let step_u32 = step as u32; let step_overflow = step_u32 as u128 != step; - let (res, overflow) = op.handle_result(op.address.overflowing_add(step_u32)); + let (res, overflow) = Self::_overflowing_inc_u32(address, prefix_len, step_u32); (res, overflow || step_overflow) } - pub const fn _overflowing_prev(address: Ipv4Addr, prefix_len: u8) -> (Ipv4Addr, bool) { + pub(crate) const fn _overflowing_prev(address: Ipv4Addr, prefix_len: u8) -> (Ipv4Addr, bool) { let op = Ipv4OverflowingOp::new(address, prefix_len); op.handle_result(op.address.overflowing_sub(1)) } - pub const fn _overflowing_dec(address: Ipv4Addr, prefix_len: u8, step: u128) -> (Ipv4Addr, bool) { + pub(crate) const fn _overflowing_dec_u32( + address: Ipv4Addr, + prefix_len: u8, + step_u32: u32, + ) -> (Ipv4Addr, bool) { let op = Ipv4OverflowingOp::new(address, prefix_len); + let (res, overflow) = op.handle_result(op.address.overflowing_sub(step_u32)); + (res, overflow) + } + + pub(crate) const fn _overflowing_dec( + address: Ipv4Addr, + prefix_len: u8, + step: u128, + ) -> (Ipv4Addr, bool) { let step_u32 = step as u32; let step_overflow = step_u32 as u128 != step; - let (res, overflow) = op.handle_result(op.address.overflowing_sub(step_u32)); + let (res, overflow) = Self::_overflowing_dec_u32(address, prefix_len, step_u32); (res, overflow || step_overflow) } - pub const fn _overflowing_sub(address: Ipv4Addr, other: Ipv4Addr) -> (u128, bool) { - let (res, overflow) = Self::to_native(address).overflowing_sub(Self::to_native(other)); - (res as u128, overflow) - } + /* + pub(crate) const fn _overflowing_sub(address: Ipv4Addr, other: Ipv4Addr) -> (u128, bool) { + let (res, overflow) = Self::to_native(address).overflowing_sub(Self::to_native(other)); + (res as u128, overflow) + } */ - pub const fn _prefix_match(address: Ipv4Addr, other: Ipv4Addr, prefix_len: u8) -> bool { + pub(crate) const fn _prefix_match(address: Ipv4Addr, other: Ipv4Addr, prefix_len: u8) -> bool { let net_mask: u32 = !Self::native_host_mask(prefix_len); (Self::to_native(address) & net_mask) == (Self::to_native(other) & net_mask) } - pub const fn _network_address(address: Ipv4Addr, prefix_len: u8) -> Ipv4Addr { + pub(crate) const fn _network_address(address: Ipv4Addr, prefix_len: u8) -> Ipv4Addr { let net_mask: u32 = !Self::native_host_mask(prefix_len); Self::from_native(Self::to_native(address) & net_mask) } - pub const fn _last_address(address: Ipv4Addr, prefix_len: u8) -> Ipv4Addr { + pub(crate) const fn _last_address(address: Ipv4Addr, prefix_len: u8) -> Ipv4Addr { let host_mask: u32 = Self::native_host_mask(prefix_len); Self::from_native(Self::to_native(address) | host_mask) } - pub const fn _network_mask(prefix_len: u8) -> Ipv4Addr { + pub(crate) const fn _network_mask(prefix_len: u8) -> Ipv4Addr { Self::from_native(!Self::native_host_mask(prefix_len)) } } @@ -173,12 +199,12 @@ impl Ipv6OverflowingOp { pub struct Ipv6AddrTools(()); impl Ipv6AddrTools { - pub const fn to_native(ip: Ipv6Addr) -> u128 { + pub(crate) const fn to_native(ip: Ipv6Addr) -> u128 { // const: u128::from u128::from_be_bytes(ip.octets()) } - pub const fn from_native(ip: u128) -> Ipv6Addr { + pub(crate) const fn from_native(ip: u128) -> Ipv6Addr { // const: Ipv6Addr::from let ip = ip.to_be_bytes(); #[cfg(not(feature = "no_unsafe"))] @@ -208,7 +234,7 @@ impl Ipv6AddrTools { } } - pub const fn native_host_mask(prefix_len: u8) -> u128 { + pub(crate) const fn native_host_mask(prefix_len: u8) -> u128 { // const: unwrap_or(0) if let Some(mask) = (!0u128).checked_shr(prefix_len as u32) { mask @@ -217,54 +243,62 @@ impl Ipv6AddrTools { } } - pub const fn _has_zero_host_part(address: Ipv6Addr, prefix_len: u8) -> bool { + pub(crate) const fn _has_zero_host_part(address: Ipv6Addr, prefix_len: u8) -> bool { let host_mask: u128 = Self::native_host_mask(prefix_len); let addr_num = Self::to_native(address); (addr_num & host_mask) == 0 } - pub const fn _overflowing_next(address: Ipv6Addr, prefix_len: u8) -> (Ipv6Addr, bool) { + pub(crate) const fn _overflowing_next(address: Ipv6Addr, prefix_len: u8) -> (Ipv6Addr, bool) { let op = Ipv6OverflowingOp::new(address, prefix_len); op.handle_result(op.address.overflowing_add(1)) } - /* - pub const fn _overflowing_inc(address: Ipv6Addr, prefix_len: u8, step: u128) -> (Ipv6Addr, bool) { + pub(crate) const fn _overflowing_inc( + address: Ipv6Addr, + prefix_len: u8, + step: u128, + ) -> (Ipv6Addr, bool) { let op = Ipv6OverflowingOp::new(address, prefix_len); op.handle_result(op.address.overflowing_add(step)) } - pub const fn _overflowing_prev(address: Ipv6Addr, prefix_len: u8) -> (Ipv6Addr, bool) { + pub(crate) const fn _overflowing_prev(address: Ipv6Addr, prefix_len: u8) -> (Ipv6Addr, bool) { let op = Ipv6OverflowingOp::new(address, prefix_len); op.handle_result(op.address.overflowing_sub(1)) } - pub const fn _overflowing_dec(address: Ipv6Addr, prefix_len: u8, step: u128) -> (Ipv6Addr, bool) { + pub(crate) const fn _overflowing_dec( + address: Ipv6Addr, + prefix_len: u8, + step: u128, + ) -> (Ipv6Addr, bool) { let op = Ipv6OverflowingOp::new(address, prefix_len); op.handle_result(op.address.overflowing_sub(step)) } - pub const fn _overflowing_sub(address: Ipv6Addr, other: Ipv6Addr) -> (u128, bool) { - Self::to_native(address).overflowing_sub(Self::to_native(other)) - } + /* + pub(crate) const fn _overflowing_sub(address: Ipv6Addr, other: Ipv6Addr) -> (u128, bool) { + Self::to_native(address).overflowing_sub(Self::to_native(other)) + } */ - pub const fn _prefix_match(address: Ipv6Addr, other: Ipv6Addr, prefix_len: u8) -> bool { + pub(crate) const fn _prefix_match(address: Ipv6Addr, other: Ipv6Addr, prefix_len: u8) -> bool { let net_mask: u128 = !Self::native_host_mask(prefix_len); (Self::to_native(address) & net_mask) == (Self::to_native(other) & net_mask) } - pub const fn _network_address(address: Ipv6Addr, prefix_len: u8) -> Ipv6Addr { + pub(crate) const fn _network_address(address: Ipv6Addr, prefix_len: u8) -> Ipv6Addr { let net_mask: u128 = !Self::native_host_mask(prefix_len); Self::from_native(Self::to_native(address) & net_mask) } - pub const fn _last_address(address: Ipv6Addr, prefix_len: u8) -> Ipv6Addr { + pub(crate) const fn _last_address(address: Ipv6Addr, prefix_len: u8) -> Ipv6Addr { let host_mask: u128 = Self::native_host_mask(prefix_len); Self::from_native(Self::to_native(address) | host_mask) } - pub const fn _network_mask(prefix_len: u8) -> Ipv6Addr { + pub(crate) const fn _network_mask(prefix_len: u8) -> Ipv6Addr { Self::from_native(!Self::native_host_mask(prefix_len)) } } @@ -275,101 +309,106 @@ impl PrivUnspecAddress for Ipv6Addr { pub struct IpAddrTools(()); +// we currently don't use the tools on IpAddr and related enums impl IpAddrTools { - pub const fn _has_zero_host_part(address: IpAddr, prefix_len: u8) -> bool { - match address { - IpAddr::V4(a) => Ipv4AddrTools::_has_zero_host_part(a, prefix_len), - IpAddr::V6(a) => Ipv6AddrTools::_has_zero_host_part(a, prefix_len), + /* + pub(crate) const fn _has_zero_host_part(address: IpAddr, prefix_len: u8) -> bool { + match address { + IpAddr::V4(a) => Ipv4AddrTools::_has_zero_host_part(a, prefix_len), + IpAddr::V6(a) => Ipv6AddrTools::_has_zero_host_part(a, prefix_len), + } } - } - pub const fn _overflowing_next(address: IpAddr, prefix_len: u8) -> (IpAddr, bool) { - match address { - IpAddr::V4(a) => { - let (res, of) = Ipv4AddrTools::_overflowing_next(a, prefix_len); - (IpAddr::V4(res), of) - }, - IpAddr::V6(a) => { - let (res, of) = Ipv6AddrTools::_overflowing_next(a, prefix_len); - (IpAddr::V6(res), of) - }, + pub(crate) const fn _overflowing_next(address: IpAddr, prefix_len: u8) -> (IpAddr, bool) { + match address { + IpAddr::V4(a) => { + let (res, of) = Ipv4AddrTools::_overflowing_next(a, prefix_len); + (IpAddr::V4(res), of) + }, + IpAddr::V6(a) => { + let (res, of) = Ipv6AddrTools::_overflowing_next(a, prefix_len); + (IpAddr::V6(res), of) + }, + } } - } - /* - pub const fn _overflowing_inc(address: IpAddr, prefix_len: u8, step: u128) -> (IpAddr, bool) { - match address { - IpAddr::V4(a) => { - let (res, of) = Ipv4AddrTools::_overflowing_inc(a, prefix_len, step); - (IpAddr::V4(res), of) - }, - IpAddr::V6(a) => { - let (res, of) = Ipv6AddrTools::_overflowing_inc(a, prefix_len, step); - (IpAddr::V6(res), of) - }, + pub(crate) const fn _overflowing_inc(address: IpAddr, prefix_len: u8, step: u128) -> (IpAddr, bool) { + match address { + IpAddr::V4(a) => { + let (res, of) = Ipv4AddrTools::_overflowing_inc(a, prefix_len, step); + (IpAddr::V4(res), of) + }, + IpAddr::V6(a) => { + let (res, of) = Ipv6AddrTools::_overflowing_inc(a, prefix_len, step); + (IpAddr::V6(res), of) + }, + } } - } - pub const fn _overflowing_prev(address: IpAddr, prefix_len: u8) -> (IpAddr, bool) { - match address { - IpAddr::V4(a) => { - let (res, of) = Ipv4AddrTools::_overflowing_prev(a, prefix_len); - (IpAddr::V4(res), of) - }, - IpAddr::V6(a) => { - let (res, of) = Ipv6AddrTools::_overflowing_prev(a, prefix_len); - (IpAddr::V6(res), of) - }, + pub(crate) const fn _overflowing_prev(address: IpAddr, prefix_len: u8) -> (IpAddr, bool) { + match address { + IpAddr::V4(a) => { + let (res, of) = Ipv4AddrTools::_overflowing_prev(a, prefix_len); + (IpAddr::V4(res), of) + }, + IpAddr::V6(a) => { + let (res, of) = Ipv6AddrTools::_overflowing_prev(a, prefix_len); + (IpAddr::V6(res), of) + }, + } } - } - pub const fn _overflowing_dec(address: IpAddr, prefix_len: u8, step: u128) -> (IpAddr, bool) { - match address { - IpAddr::V4(a) => { - let (res, of) = Ipv4AddrTools::_overflowing_dec(a, prefix_len, step); - (IpAddr::V4(res), of) - }, - IpAddr::V6(a) => { - let (res, of) = Ipv6AddrTools::_overflowing_dec(a, prefix_len, step); - (IpAddr::V6(res), of) - }, + pub(crate) const fn _overflowing_dec(address: IpAddr, prefix_len: u8, step: u128) -> (IpAddr, bool) { + match address { + IpAddr::V4(a) => { + let (res, of) = Ipv4AddrTools::_overflowing_dec(a, prefix_len, step); + (IpAddr::V4(res), of) + }, + IpAddr::V6(a) => { + let (res, of) = Ipv6AddrTools::_overflowing_dec(a, prefix_len, step); + (IpAddr::V6(res), of) + }, + } } - } + */ - pub const fn _overflowing_sub(address: IpAddr, other: IpAddr) -> (u128, bool) { - match (address, other) { - (IpAddr::V4(a), IpAddr::V4(other)) => Ipv4AddrTools::_overflowing_sub(a, other), - (IpAddr::V6(a), IpAddr::V6(other)) => Ipv6AddrTools::_overflowing_sub(a, other), - _ => (0, false), + /* + pub(crate) const fn _overflowing_sub(address: IpAddr, other: IpAddr) -> (u128, bool) { + match (address, other) { + (IpAddr::V4(a), IpAddr::V4(other)) => Ipv4AddrTools::_overflowing_sub(a, other), + (IpAddr::V6(a), IpAddr::V6(other)) => Ipv6AddrTools::_overflowing_sub(a, other), + _ => (0, false), + } } - } */ - fn _prefix_match(address: IpAddr, other: IpAddr, prefix_len: u8) -> bool { - match (address, other) { - (IpAddr::V4(a), IpAddr::V4(other)) => { - Ipv4AddrTools::_prefix_match(a, other, prefix_len) - }, - (IpAddr::V6(a), IpAddr::V6(other)) => { - Ipv6AddrTools::_prefix_match(a, other, prefix_len) - }, - _ => false, + /* + fn _prefix_match(address: IpAddr, other: IpAddr, prefix_len: u8) -> bool { + match (address, other) { + (IpAddr::V4(a), IpAddr::V4(other)) => { + Ipv4AddrTools::_prefix_match(a, other, prefix_len) + }, + (IpAddr::V6(a), IpAddr::V6(other)) => { + Ipv6AddrTools::_prefix_match(a, other, prefix_len) + }, + _ => false, + } } - } - pub const fn _network_address(address: IpAddr, prefix_len: u8) -> IpAddr { - match address { - IpAddr::V4(a) => IpAddr::V4(Ipv4AddrTools::_network_address(a, prefix_len)), - IpAddr::V6(a) => IpAddr::V6(Ipv6AddrTools::_network_address(a, prefix_len)), + pub(crate) const fn _network_address(address: IpAddr, prefix_len: u8) -> IpAddr { + match address { + IpAddr::V4(a) => IpAddr::V4(Ipv4AddrTools::_network_address(a, prefix_len)), + IpAddr::V6(a) => IpAddr::V6(Ipv6AddrTools::_network_address(a, prefix_len)), + } } - } - fn _last_address(address: IpAddr, prefix_len: u8) -> IpAddr { - match address { - IpAddr::V4(a) => IpAddr::V4(Ipv4AddrTools::_last_address(a, prefix_len)), - IpAddr::V6(a) => IpAddr::V6(Ipv6AddrTools::_last_address(a, prefix_len)), + fn _last_address(address: IpAddr, prefix_len: u8) -> IpAddr { + match address { + IpAddr::V4(a) => IpAddr::V4(Ipv4AddrTools::_last_address(a, prefix_len)), + IpAddr::V6(a) => IpAddr::V6(Ipv6AddrTools::_last_address(a, prefix_len)), + } } - } + */ } impl PrivUnspecAddress for IpAddr { diff --git a/src/traits.rs b/src/traits.rs index 5cc46ac..f24e782 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -141,6 +141,23 @@ pub trait Inet: Copy + Debug + Ord + Hash + PrivInet { /// Returns next address in network or `None` if it was the last address in the network fn next(self) -> Option; + /// decrements host part (without changing the network part); + /// returns true on wrap around + fn decrement(&mut self) -> bool; + + /// Returns previous address in network or `None` if it was the first address in the network + fn previous(self) -> Option; + + /// Find the nth host after the current one in the current network + /// + /// Returned boolean indicates whether an overflow occured. + fn overflowing_add(self, step: u128) -> (Self, bool); + + /// Find the nth host before the current one in the current network + /// + /// Returned boolean indicates whether an overflow occured. + fn overflowing_sub(self, step: u128) -> (Self, bool); + /// network (i.e. drops the host information) fn network(&self) -> ::Cidr;