ip/concrete/prefix/
mod.rs1#![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#[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 #[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 pub const DEFAULT: Self = Self {
51 prefix: Address::ZEROS,
52 length: PrefixLength::MIN,
53 };
54
55 pub fn new(mut prefix: Address<A>, length: PrefixLength<A>) -> Self {
59 prefix &= Netmask::from(length);
60 Self { prefix, length }
61 }
62
63 pub const fn prefix(&self) -> Address<A> {
65 self.prefix
66 }
67
68 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}