ip/concrete/prefix/
mod.rs

1#![allow(clippy::module_name_repetitions)]
2
3use core::cmp::min;
4use core::fmt;
5use core::str::FromStr;
6
7use super::{common_length, impl_try_from_any, Address, Bitmask, Hostmask, Interface, Netmask};
8use crate::{
9    any,
10    error::Error,
11    fmt::AddressDisplay,
12    traits::{self, primitive::Address as _, Afi, PrefixLength as _},
13    Ipv4, Ipv6,
14};
15
16mod len;
17pub use self::len::PrefixLength;
18
19mod ord;
20pub use self::ord::PrefixOrdering;
21
22mod range;
23pub use self::range::Range;
24
25#[cfg(feature = "std")]
26// TODO: remove `unknown_lints` dance when `clippy::unnecessary_box_returns` is stabilised
27#[allow(unknown_lints)]
28#[allow(clippy::unnecessary_box_returns)]
29#[warn(unknown_lints)]
30mod set;
31#[cfg(feature = "std")]
32pub use self::set::Set;
33
34mod subprefixes;
35pub use self::subprefixes::Subprefixes;
36
37#[allow(clippy::wildcard_imports)]
38mod private {
39    use super::*;
40
41    /// An IP prefix, consisting of a network address and prefix length.
42    #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
43    pub struct Prefix<A: Afi> {
44        prefix: Address<A>,
45        length: PrefixLength<A>,
46    }
47
48    impl<A: Afi> Prefix<A> {
49        /// The "default" prefix containing all addresses of address family `A`.
50        pub const DEFAULT: Self = Self {
51            prefix: Address::ZEROS,
52            length: PrefixLength::MIN,
53        };
54
55        /// Construct a new [`Prefix<A>`] from an address and prefix length.
56        ///
57        /// The host bits of `prefix` will be automatically set to zero.
58        pub fn new(mut prefix: Address<A>, length: PrefixLength<A>) -> Self {
59            prefix &= Netmask::from(length);
60            Self { prefix, length }
61        }
62
63        /// Get the network address of this prefix.
64        pub const fn prefix(&self) -> Address<A> {
65            self.prefix
66        }
67
68        /// Get the length of this prefix.
69        pub const fn length(&self) -> PrefixLength<A> {
70            self.length
71        }
72    }
73}
74
75pub use self::private::Prefix;
76
77impl<A: Afi> Prefix<A> {
78    fn common_with(&self, other: &Self) -> Self {
79        let min_length = min(self.length(), other.length());
80        let common_length = common_length(self.prefix(), other.prefix());
81        let length = min(min_length, common_length);
82        Self::new(self.prefix(), length)
83    }
84
85    fn map_addr<F>(&self, f: F) -> Option<Self>
86    where
87        F: FnOnce(Address<A>) -> Option<Address<A>>,
88    {
89        f(self.prefix()).map(|addr| Self::new(addr, self.length()))
90    }
91}
92
93impl<A: Afi> traits::Prefix for Prefix<A> {
94    type Address = Address<A>;
95    type Length = PrefixLength<A>;
96    type Hostmask = Hostmask<A>;
97    type Netmask = Netmask<A>;
98    type Subprefixes = Subprefixes<A>;
99
100    fn network(&self) -> Self::Address {
101        self.prefix()
102    }
103
104    fn hostmask(&self) -> Self::Hostmask {
105        self.length().into()
106    }
107
108    fn netmask(&self) -> Self::Netmask {
109        self.length().into()
110    }
111
112    fn max_prefix_len(&self) -> Self::Length {
113        Self::Length::MAX
114    }
115
116    fn prefix_len(&self) -> Self::Length {
117        self.length()
118    }
119
120    fn broadcast(&self) -> Self::Address {
121        self.network() | self.hostmask()
122    }
123
124    fn supernet(&self) -> Option<Self> {
125        self.length()
126            .decrement()
127            .map(|len| Self::new(self.prefix(), len))
128            .ok()
129    }
130
131    fn is_sibling(&self, other: &Self) -> bool {
132        self.supernet() == other.supernet()
133    }
134
135    fn subprefixes(&self, new_prefix_len: Self::Length) -> Result<Self::Subprefixes, Error> {
136        Self::Subprefixes::new(*self, new_prefix_len)
137    }
138
139    fn new_prefix_length(&self, length: u8) -> Result<Self::Length, Error> {
140        (length as usize).try_into()
141    }
142}
143
144impl<A: Afi> From<Address<A>> for Prefix<A> {
145    fn from(addr: Address<A>) -> Self {
146        Self::new(addr, PrefixLength::MAX)
147    }
148}
149
150impl<A: Afi> From<Interface<A>> for Prefix<A> {
151    fn from(interface: Interface<A>) -> Self {
152        Self::new(interface.address(), interface.length())
153    }
154}
155
156impl<A: Afi> FromStr for Prefix<A> {
157    type Err = Error;
158
159    fn from_str(s: &str) -> Result<Self, Self::Err> {
160        A::Primitive::parse_prefix(s).and_then(|(addr, len)| {
161            Ok(Self::new(
162                Address::new(addr),
163                PrefixLength::from_primitive(len)?,
164            ))
165        })
166    }
167}
168
169impl_try_from_any! {
170    any::Prefix {
171        any::Prefix::Ipv4 => Prefix<Ipv4>,
172        any::Prefix::Ipv6 => Prefix<Ipv6>,
173    }
174}
175
176impl<A: Afi> fmt::Display for Prefix<A>
177where
178    A::Primitive: AddressDisplay<A>,
179{
180    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181        write!(f, "{}/{}", self.prefix(), self.length())
182    }
183}
184
185#[cfg(feature = "ipnet")]
186impl From<ipnet::Ipv4Net> for Prefix<Ipv4> {
187    fn from(net: ipnet::Ipv4Net) -> Self {
188        let prefix = net.network().into();
189        let length = PrefixLength::from_primitive(net.prefix_len())
190            .expect("we trusted `ipnet` to enforce length bounds");
191        Self::new(prefix, length)
192    }
193}
194
195#[cfg(feature = "ipnet")]
196impl From<ipnet::Ipv6Net> for Prefix<Ipv6> {
197    fn from(net: ipnet::Ipv6Net) -> Self {
198        let prefix = net.network().into();
199        let length = PrefixLength::from_primitive(net.prefix_len())
200            .expect("we trusted `ipnet` to enforce length bounds");
201        Self::new(prefix, length)
202    }
203}
204
205#[cfg(any(test, feature = "arbitrary"))]
206use proptest::{
207    arbitrary::{any_with, Arbitrary, ParamsFor, StrategyFor},
208    strategy::{BoxedStrategy, Strategy},
209};
210
211#[cfg(any(test, feature = "arbitrary"))]
212impl<A: Afi> Arbitrary for Prefix<A>
213where
214    Address<A>: Arbitrary,
215    StrategyFor<Address<A>>: 'static,
216    PrefixLength<A>: Arbitrary,
217    StrategyFor<PrefixLength<A>>: 'static,
218{
219    type Parameters = ParamsFor<(Address<A>, PrefixLength<A>)>;
220    type Strategy = BoxedStrategy<Self>;
221
222    fn arbitrary_with(params: Self::Parameters) -> Self::Strategy {
223        (
224            any_with::<Address<A>>(params.0),
225            any_with::<PrefixLength<A>>(params.1),
226        )
227            .prop_map(|(prefix, length)| Self::new(prefix, length))
228            .boxed()
229    }
230}