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
15pub mod types;
17use self::types::{Bit, Host, Net, Type};
18
19pub type Netmask<A> = Mask<Net, A>;
21
22pub type Hostmask<A> = Mask<Host, A>;
24
25pub type Bitmask<A> = Mask<Bit, A>;
27
28impl<A: Afi, T: Type> Mask<T, A> {
29 pub const ZEROS: Self = Self::new(A::Primitive::ZERO);
31
32 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
125impl<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}