ip/concrete/mask/
mod.rs

1use core::fmt;
2use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr};
3
4use super::{impl_try_from_any, Address, PrefixLength};
5use crate::{
6    any,
7    fmt::AddressDisplay,
8    traits::{self, primitive::Address as _, Afi},
9    Ipv4, Ipv6,
10};
11
12mod private;
13pub use self::private::Mask;
14
15/// Types of IP address mask.
16pub mod types;
17use self::types::{Bit, Host, Net, Type};
18
19/// An IP Netmask.
20pub type Netmask<A> = Mask<Net, A>;
21
22/// An IP Hostmask.
23pub type Hostmask<A> = Mask<Host, A>;
24
25/// An address bit-mask.
26pub type Bitmask<A> = Mask<Bit, A>;
27
28impl<A: Afi, T: Type> Mask<T, A> {
29    /// The "all-zeros" mask.
30    pub const ZEROS: Self = Self::new(A::Primitive::ZERO);
31
32    /// The "all-ones" mask.
33    pub const ONES: Self = Self::new(A::Primitive::ONES);
34}
35
36impl<T: Type, A: Afi> traits::Mask for Mask<T, A> {}
37impl<A: Afi> traits::Netmask for Netmask<A> {}
38impl<A: Afi> traits::Hostmask for Hostmask<A> {}
39impl<A: Afi> traits::Bitmask for Bitmask<A> {}
40
41impl<A: Afi> From<PrefixLength<A>> for Netmask<A> {
42    fn from(len: PrefixLength<A>) -> Self {
43        Self::ONES << -len
44    }
45}
46
47impl<A: Afi> From<PrefixLength<A>> for Hostmask<A> {
48    fn from(len: PrefixLength<A>) -> Self {
49        Self::ONES >> len
50    }
51}
52
53impl<A: Afi> From<Address<A>> for Bitmask<A> {
54    fn from(addr: Address<A>) -> Self {
55        Self::new(addr.into_primitive())
56    }
57}
58
59impl_try_from_any! {
60    any::Netmask {
61        any::Netmask::Ipv4 => Netmask<Ipv4>,
62        any::Netmask::Ipv6 => Netmask<Ipv6>,
63    }
64}
65
66impl_try_from_any! {
67    any::Hostmask {
68        any::Hostmask::Ipv4 => Hostmask<Ipv4>,
69        any::Hostmask::Ipv6 => Hostmask<Ipv6>,
70    }
71}
72
73impl<A: Afi, T: Type> Shl<PrefixLength<A>> for Mask<T, A> {
74    type Output = Self;
75
76    fn shl(self, rhs: PrefixLength<A>) -> Self::Output {
77        if rhs == PrefixLength::<A>::MAX {
78            Self::ZEROS
79        } else {
80            Self::new(Self::into_primitive(self) << rhs.into_primitive())
81        }
82    }
83}
84
85impl<A: Afi, T: Type> Shr<PrefixLength<A>> for Mask<T, A> {
86    type Output = Self;
87
88    fn shr(self, rhs: PrefixLength<A>) -> Self::Output {
89        if rhs == PrefixLength::<A>::MAX {
90            Self::ZEROS
91        } else {
92            Self::new(Self::into_primitive(self) >> rhs.into_primitive())
93        }
94    }
95}
96
97impl<A: Afi, T1: Type, T2: Type> BitAnd<Mask<T2, A>> for Mask<T1, A> {
98    type Output = Bitmask<A>;
99    fn bitand(self, rhs: Mask<T2, A>) -> Self::Output {
100        Self::Output::new(self.into_primitive() & rhs.into_primitive())
101    }
102}
103
104impl<A: Afi, T: Type> BitOr<Mask<T, A>> for Bitmask<A> {
105    type Output = Self;
106    fn bitor(self, rhs: Mask<T, A>) -> Self {
107        Self::new(self.into_primitive() | rhs.into_primitive())
108    }
109}
110
111impl<A: Afi, T: Type> BitXor<Mask<T, A>> for Bitmask<A> {
112    type Output = Self;
113    fn bitxor(self, rhs: Mask<T, A>) -> Self {
114        Self::new(self.into_primitive() ^ rhs.into_primitive())
115    }
116}
117
118impl<A: Afi> Not for Bitmask<A> {
119    type Output = Self;
120    fn not(self) -> Self {
121        Self::new(self.into_primitive().not())
122    }
123}
124
125// TODO: impl FromStr
126
127impl<A: Afi, T: Type> fmt::Display for Mask<T, A>
128where
129    A::Primitive: AddressDisplay<A>,
130{
131    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132        self.into_primitive().fmt_addr(f)
133    }
134}
135
136#[cfg(any(test, feature = "arbitrary"))]
137use proptest::{
138    arbitrary::{any_with, Arbitrary, ParamsFor, StrategyFor},
139    strategy::{BoxedStrategy, Strategy},
140};
141
142#[cfg(any(test, feature = "arbitrary"))]
143impl<A, T> Arbitrary for Mask<T, A>
144where
145    A: Afi + 'static,
146    A::Primitive: 'static,
147    T: Type + 'static,
148    Self: From<PrefixLength<A>>,
149    PrefixLength<A>: Arbitrary,
150    StrategyFor<PrefixLength<A>>: 'static,
151{
152    type Parameters = ParamsFor<PrefixLength<A>>;
153    type Strategy = BoxedStrategy<Self>;
154
155    fn arbitrary_with(params: Self::Parameters) -> Self::Strategy {
156        any_with::<PrefixLength<A>>(params)
157            .prop_map(Self::from)
158            .boxed()
159    }
160}