1use core::fmt;
4
5pub trait NetworkAddress: Clone + Copy + fmt::Debug + fmt::Display + PartialEq + Eq + PartialOrd + Ord {
7 const BITS_LEN: u8;
9}
10
11#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
12pub struct Cidr<A> {
14 prefix: u8,
15 addr: A,
16}
17
18impl<A: NetworkAddress> Cidr<A> {
19 #[inline]
20 pub const fn new(addr: A, prefix: u8) -> Option<Self> {
24 if prefix > A::BITS_LEN {
25 None
26 } else {
27 Some(Self {
28 addr,
29 prefix,
30 })
31 }
32 }
33
34 #[inline]
35 pub const fn new_single(addr: A) -> Self {
37 Self {
38 addr,
39 prefix: A::BITS_LEN
40 }
41 }
42
43 #[inline(always)]
44 pub const fn addr(&self) -> A {
46 self.addr
47 }
48
49 #[inline(always)]
50 pub const fn prefix(&self) -> u8 {
52 self.prefix
53 }
54}
55
56impl<A: NetworkAddress> fmt::Display for Cidr<A> {
57 #[inline(always)]
58 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
59 let Self { addr, prefix } = self;
60 fmt.write_fmt(format_args!("{addr}/{prefix}"))
61 }
62}
63
64macro_rules! impl_base_methods {
65 ($typ:ty where REPR=$repr:ident) => {
66 #[inline]
67 pub const fn mask(prefix: u8) -> $typ {
69 match prefix {
70 0 => <$typ>::UNSPECIFIED,
71 prefix => {
72 let mask = $repr::MAX << (BITS_LEN.saturating_sub(prefix));
73 <$typ>::from_bits(mask)
74 }
75 }
76 }
77
78 #[inline]
79 pub const fn network_addr(addr: $typ, prefix: u8) -> $typ {
81 let mask = mask(prefix).to_bits();
82 let addr = addr.to_bits() & mask;
83 <$typ>::from_bits(addr)
84 }
85
86 #[inline]
87 pub const fn broadcast_addr(addr: $typ, prefix: u8) -> $typ {
89 let mask = mask(prefix).to_bits();
90 let broadcast = addr.to_bits() | !mask;
91 <$typ>::from_bits(broadcast)
92 }
93
94 #[inline]
95 pub const fn size(prefix: u8) -> $repr {
97 match prefix {
98 0 => $repr::MAX,
99 prefix => 1 << (BITS_LEN.saturating_sub(prefix))
100 }
101 }
102
103 impl $crate::base::Cidr<$typ> {
104 #[inline(always)]
105 pub const fn network_addr(&self) -> $typ {
107 network_addr(self.addr(), self.prefix())
108 }
109
110 #[inline(always)]
111 pub const fn broadcast_addr(&self) -> $typ {
113 broadcast_addr(self.addr(), self.prefix())
114 }
115
116 #[inline(always)]
117 pub const fn contains(&self, addr: $typ) -> bool {
119 (addr.to_bits() & mask(self.prefix()).to_bits()) == self.network_addr().to_bits()
120 }
121
122 #[inline(always)]
123 pub const fn size(&self) -> $repr {
125 size(self.prefix())
126 }
127
128 #[inline(always)]
129 pub const fn get(&self, idx: $repr) -> Option<$typ> {
131 if idx >= self.size() {
132 return None;
133 }
134
135 Some(self.get_unchecked(idx))
136 }
137
138 #[inline]
139 pub const fn get_unchecked(&self, idx: $repr) -> $typ {
144 let net = self.network_addr().to_bits();
145 <$typ>::from_bits(net.wrapping_add(idx))
146 }
147 }
148 }
149}
150
151pub(super) use impl_base_methods;