1use core::fmt;
4use core::iter::FusedIterator;
5use core::net::{Ipv4Addr, SocketAddrV4};
6
7use crate::{
8 BvllError, BvllSink, SinkFull, BDT_ENTRY_LENGTH, BIP_ADDRESS_LENGTH, FDT_ENTRY_LENGTH,
9};
10
11const ENTRY_LENGTH: usize = BDT_ENTRY_LENGTH;
14const _: () = assert!(FDT_ENTRY_LENGTH == ENTRY_LENGTH);
15
16#[must_use]
28pub const fn address_to_octets(address: SocketAddrV4) -> [u8; BIP_ADDRESS_LENGTH] {
29 let [a, b, c, d] = address.ip().octets();
30 let [high, low] = address.port().to_be_bytes();
31 [a, b, c, d, high, low]
32}
33
34#[must_use]
36pub const fn address_from_octets(octets: [u8; BIP_ADDRESS_LENGTH]) -> SocketAddrV4 {
37 let [a, b, c, d, high, low] = octets;
38 SocketAddrV4::new(Ipv4Addr::new(a, b, c, d), u16::from_be_bytes([high, low]))
39}
40
41pub fn address_from_slice(octets: &[u8]) -> Result<SocketAddrV4, BvllError> {
43 match <[u8; BIP_ADDRESS_LENGTH]>::try_from(octets) {
44 Ok(octets) => Ok(address_from_octets(octets)),
45 Err(_) => Err(BvllError::AddressLength {
46 length: octets.len(),
47 }),
48 }
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
59pub struct BdtEntry {
60 pub address: SocketAddrV4,
62 pub mask: Ipv4Addr,
64}
65
66impl BdtEntry {
67 #[must_use]
69 pub const fn new(address: SocketAddrV4, mask: Ipv4Addr) -> Self {
70 Self { address, mask }
71 }
72
73 #[must_use]
75 pub const fn to_octets(self) -> [u8; ENTRY_LENGTH] {
76 let [a, b, c, d, high, low] = address_to_octets(self.address);
77 let [m0, m1, m2, m3] = self.mask.octets();
78 [a, b, c, d, high, low, m0, m1, m2, m3]
79 }
80
81 #[must_use]
83 pub const fn from_octets(octets: [u8; ENTRY_LENGTH]) -> Self {
84 let [a, b, c, d, high, low, m0, m1, m2, m3] = octets;
85 Self {
86 address: address_from_octets([a, b, c, d, high, low]),
87 mask: Ipv4Addr::new(m0, m1, m2, m3),
88 }
89 }
90}
91
92#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
97pub struct FdtEntry {
98 pub address: SocketAddrV4,
100 pub ttl: u16,
102 pub remaining: u16,
104}
105
106impl FdtEntry {
107 #[must_use]
109 pub const fn new(address: SocketAddrV4, ttl: u16, remaining: u16) -> Self {
110 Self {
111 address,
112 ttl,
113 remaining,
114 }
115 }
116
117 #[must_use]
120 pub const fn to_octets(self) -> [u8; ENTRY_LENGTH] {
121 let [a, b, c, d, high, low] = address_to_octets(self.address);
122 let [t0, t1] = self.ttl.to_be_bytes();
123 let [r0, r1] = self.remaining.to_be_bytes();
124 [a, b, c, d, high, low, t0, t1, r0, r1]
125 }
126
127 #[must_use]
129 pub const fn from_octets(octets: [u8; ENTRY_LENGTH]) -> Self {
130 let [a, b, c, d, high, low, t0, t1, r0, r1] = octets;
131 Self {
132 address: address_from_octets([a, b, c, d, high, low]),
133 ttl: u16::from_be_bytes([t0, t1]),
134 remaining: u16::from_be_bytes([r0, r1]),
135 }
136 }
137}
138
139mod sealed {
140 pub trait Sealed {}
141 impl Sealed for super::BdtEntry {}
142 impl Sealed for super::FdtEntry {}
143}
144
145pub trait TableEntry: Copy + sealed::Sealed {
147 fn from_wire(octets: [u8; ENTRY_LENGTH]) -> Self;
149 fn to_wire(self) -> [u8; ENTRY_LENGTH];
151}
152
153impl TableEntry for BdtEntry {
154 fn from_wire(octets: [u8; ENTRY_LENGTH]) -> Self {
155 Self::from_octets(octets)
156 }
157 fn to_wire(self) -> [u8; ENTRY_LENGTH] {
158 self.to_octets()
159 }
160}
161
162impl TableEntry for FdtEntry {
163 fn from_wire(octets: [u8; ENTRY_LENGTH]) -> Self {
164 Self::from_octets(octets)
165 }
166 fn to_wire(self) -> [u8; ENTRY_LENGTH] {
167 self.to_octets()
168 }
169}
170
171#[derive(Clone, Copy)]
176pub struct Entries<'a, T> {
177 repr: Repr<'a, T>,
178}
179
180#[derive(Clone, Copy)]
181enum Repr<'a, T> {
182 Wire(&'a [[u8; ENTRY_LENGTH]]),
183 Typed(&'a [T]),
184}
185
186pub type BdtEntries<'a> = Entries<'a, BdtEntry>;
188pub type FdtEntries<'a> = Entries<'a, FdtEntry>;
190
191impl<'a, T: TableEntry> Entries<'a, T> {
192 pub fn from_wire(octets: &'a [u8]) -> Result<Self, BvllError> {
211 match octets.as_chunks::<ENTRY_LENGTH>() {
212 (entries, []) => Ok(Self {
213 repr: Repr::Wire(entries),
214 }),
215 _ => Err(BvllError::TableLength {
216 length: octets.len(),
217 entry_length: ENTRY_LENGTH,
218 }),
219 }
220 }
221
222 #[must_use]
224 pub const fn from_entries(entries: &'a [T]) -> Self {
225 Self {
226 repr: Repr::Typed(entries),
227 }
228 }
229
230 #[must_use]
232 pub const fn len(&self) -> usize {
233 match self.repr {
234 Repr::Wire(entries) => entries.len(),
235 Repr::Typed(entries) => entries.len(),
236 }
237 }
238
239 #[must_use]
241 pub const fn is_empty(&self) -> bool {
242 self.len() == 0
243 }
244
245 #[must_use]
247 pub fn iter(&self) -> EntryIter<'a, T> {
248 EntryIter {
249 repr: match self.repr {
250 Repr::Wire(entries) => IterRepr::Wire(entries.iter()),
251 Repr::Typed(entries) => IterRepr::Typed(entries.iter()),
252 },
253 }
254 }
255
256 pub(crate) const fn wire_length(&self) -> usize {
258 self.len() * ENTRY_LENGTH
259 }
260
261 pub(crate) fn write_to<S: BvllSink + ?Sized>(&self, sink: &mut S) -> Result<(), SinkFull> {
263 match self.repr {
264 Repr::Wire(entries) => sink.write(entries.as_flattened()),
265 Repr::Typed(entries) => entries
266 .iter()
267 .try_for_each(|entry| sink.write(&entry.to_wire())),
268 }
269 }
270}
271
272impl<T: TableEntry + PartialEq> PartialEq for Entries<'_, T> {
273 fn eq(&self, other: &Self) -> bool {
274 self.iter().eq(other.iter())
275 }
276}
277
278impl<T: TableEntry + Eq> Eq for Entries<'_, T> {}
279
280impl<T: TableEntry + fmt::Debug> fmt::Debug for Entries<'_, T> {
281 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
282 f.debug_list().entries(self.iter()).finish()
283 }
284}
285
286impl<'a, T: TableEntry> IntoIterator for Entries<'a, T> {
287 type Item = T;
288 type IntoIter = EntryIter<'a, T>;
289
290 fn into_iter(self) -> Self::IntoIter {
291 self.iter()
292 }
293}
294
295impl<'a, T: TableEntry> IntoIterator for &Entries<'a, T> {
296 type Item = T;
297 type IntoIter = EntryIter<'a, T>;
298
299 fn into_iter(self) -> Self::IntoIter {
300 self.iter()
301 }
302}
303
304#[derive(Debug, Clone)]
306pub struct EntryIter<'a, T> {
307 repr: IterRepr<'a, T>,
308}
309
310#[derive(Debug, Clone)]
311enum IterRepr<'a, T> {
312 Wire(core::slice::Iter<'a, [u8; ENTRY_LENGTH]>),
313 Typed(core::slice::Iter<'a, T>),
314}
315
316impl<T: TableEntry> Iterator for EntryIter<'_, T> {
317 type Item = T;
318
319 fn next(&mut self) -> Option<T> {
320 match &mut self.repr {
321 IterRepr::Wire(entries) => entries.next().map(|octets| T::from_wire(*octets)),
322 IterRepr::Typed(entries) => entries.next().copied(),
323 }
324 }
325
326 fn size_hint(&self) -> (usize, Option<usize>) {
327 match &self.repr {
328 IterRepr::Wire(entries) => entries.size_hint(),
329 IterRepr::Typed(entries) => entries.size_hint(),
330 }
331 }
332}
333
334impl<T: TableEntry> DoubleEndedIterator for EntryIter<'_, T> {
335 fn next_back(&mut self) -> Option<T> {
336 match &mut self.repr {
337 IterRepr::Wire(entries) => entries.next_back().map(|octets| T::from_wire(*octets)),
338 IterRepr::Typed(entries) => entries.next_back().copied(),
339 }
340 }
341}
342
343impl<T: TableEntry> ExactSizeIterator for EntryIter<'_, T> {}
344
345impl<T: TableEntry> FusedIterator for EntryIter<'_, T> {}