awdl_frame_parser/tlvs/sync_elect/
sync_tree_tlv.rs

1use core::fmt::Display;
2
3use mac_parser::MACAddress;
4use scroll::{
5    ctx::{MeasureWith, TryFromCtx, TryIntoCtx},
6    Pread, Pwrite,
7};
8
9use crate::tlvs::{AWDLTLVType, AwdlTlv};
10
11#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
12pub struct ReadMACIterator<'a> {
13    bytes: &'a [u8],
14    offset: usize,
15}
16impl<'a> ReadMACIterator<'a> {
17    pub const fn new(bytes: &'a [u8]) -> Self {
18        Self { bytes, offset: 0 }
19    }
20}
21impl Iterator for ReadMACIterator<'_> {
22    type Item = MACAddress;
23    fn next(&mut self) -> Option<Self::Item> {
24        self.bytes.gread(&mut self.offset).ok()
25    }
26}
27impl ExactSizeIterator for ReadMACIterator<'_> {
28    fn len(&self) -> usize {
29        self.bytes.len() / 6
30    }
31}
32impl Display for ReadMACIterator<'_> {
33    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
34        f.debug_list().entries(*self).finish()
35    }
36}
37
38#[derive(Clone, Copy, Debug, Default, Hash)]
39/// This describes the structure of the AWDL mesh.
40/// The contained mac address are in descending order,
41/// with the first one being the mesh master and the other ones being sync masters.
42pub struct SyncTreeTLV<I> {
43    /// The MACs.
44    pub tree: I,
45}
46impl<I> AwdlTlv for SyncTreeTLV<I> {
47    const TLV_TYPE: AWDLTLVType = AWDLTLVType::SynchronizationTree;
48}
49impl<LhsIterator, RhsIterator> PartialEq<SyncTreeTLV<RhsIterator>> for SyncTreeTLV<LhsIterator>
50where
51    LhsIterator: IntoIterator<Item = MACAddress> + Clone,
52    RhsIterator: IntoIterator<Item = MACAddress> + Clone,
53{
54    fn eq(&self, other: &SyncTreeTLV<RhsIterator>) -> bool {
55        self.tree.clone().into_iter().eq(other.tree.clone())
56    }
57}
58impl<I: IntoIterator<Item = MACAddress> + Clone> Eq for SyncTreeTLV<I> {}
59impl<I> MeasureWith<()> for SyncTreeTLV<I>
60where
61    I: ExactSizeIterator,
62{
63    fn measure_with(&self, _ctx: &()) -> usize {
64        self.tree.len() * 6
65    }
66}
67impl<'a> TryFromCtx<'a> for SyncTreeTLV<ReadMACIterator<'a>> {
68    type Error = scroll::Error;
69    fn try_from_ctx(from: &'a [u8], _ctx: ()) -> Result<(Self, usize), Self::Error> {
70        Ok((
71            Self {
72                tree: ReadMACIterator::new(from),
73            },
74            from.len() / 6,
75        ))
76    }
77}
78impl<I> TryIntoCtx for SyncTreeTLV<I>
79where
80    I: IntoIterator<Item = MACAddress>,
81{
82    type Error = scroll::Error;
83    fn try_into_ctx(self, buf: &mut [u8], _ctx: ()) -> Result<usize, Self::Error> {
84        let mut offset = 0;
85        for address in self.tree {
86            buf.gwrite(address.as_slice(), &mut offset)?;
87        }
88        Ok(offset)
89    }
90}
91
92/// The sync tree returned by reading.
93pub type DefaultSyncTreeTLV<'a> = SyncTreeTLV<ReadMACIterator<'a>>;
94
95#[cfg(test)]
96#[test]
97fn test_sync_tree_tlv() {
98    use alloc::vec;
99    use mac_parser::ZERO;
100    use scroll::Pread;
101
102    let bytes = &include_bytes!("../../../test_bins/sync_tree_tlv.bin")[3..];
103
104    let sync_tree_tlv = bytes.pread::<SyncTreeTLV<_>>(0).unwrap();
105    assert_eq!(
106        sync_tree_tlv,
107        SyncTreeTLV {
108            tree: [MACAddress::new([0xbe, 0x70, 0xf3, 0x17, 0x21, 0xf2]), ZERO]
109        }
110    );
111
112    let mut buf = vec![0x00; sync_tree_tlv.measure_with(&())];
113    buf.pwrite(sync_tree_tlv, 0).unwrap();
114    assert_eq!(buf, bytes);
115}