awdl_frame_parser/tlvs/sync_elect/channel_sequence_tlv/
channel_sequence.rs

1use core::fmt::Debug;
2use scroll::{
3    ctx::{MeasureWith, TryFromCtx, TryIntoCtx},
4    Pread, Pwrite,
5};
6
7use super::channel::*;
8
9#[derive(Clone, PartialEq, Eq)]
10/// The different types of channel sequences.
11pub enum ChannelSequence {
12    /// This en'codes just the channel.
13    Simple([u8; 16]),
14    /// This encodes channel flags and the channel it self.
15    Legacy([(LegacyFlags, u8); 16]),
16    /// This encodes first the channel and then the channels opclass.
17    OpClass([(u8, u8); 16]),
18}
19impl ChannelSequence {
20    #[inline]
21    /// Returns the channel encoding of the channel sequence.
22    pub const fn channel_encoding(&self) -> ChannelEncoding {
23        match self {
24            Self::Simple(_) => ChannelEncoding::Simple,
25            Self::Legacy(_) => ChannelEncoding::Legacy,
26            Self::OpClass(_) => ChannelEncoding::OpClass,
27        }
28    }
29    #[inline]
30    /// Generates a repeating channel sequence with the argument.
31    pub const fn fixed_channel_sequence(channel: Channel) -> Self {
32        match channel {
33            Channel::Simple { channel } => ChannelSequence::Simple([channel; 16]),
34            Channel::Legacy { flags, channel } => ChannelSequence::Legacy([(flags, channel); 16]),
35            Channel::OpClass { channel, opclass } => {
36                ChannelSequence::OpClass([(channel, opclass); 16])
37            }
38        }
39    }
40}
41impl Default for ChannelSequence {
42    fn default() -> Self {
43        ChannelSequence::Simple(Default::default())
44    }
45}
46impl Debug for ChannelSequence {
47    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
48        match self {
49            ChannelSequence::Simple(channels) => f.debug_list().entries(channels.iter()).finish(),
50            ChannelSequence::Legacy(channels) => f
51                .debug_list()
52                .entries(channels.iter().map(|(_, channel)| channel))
53                .finish(),
54            ChannelSequence::OpClass(channels) => f
55                .debug_list()
56                .entries(channels.iter().map(|(channel, _)| channel))
57                .finish(),
58        }
59    }
60}
61impl MeasureWith<()> for ChannelSequence {
62    fn measure_with(&self, _ctx: &()) -> usize {
63        16 * match self {
64            ChannelSequence::Legacy(_) | ChannelSequence::OpClass(_) => 2,
65            _ => 1,
66        }
67    }
68}
69impl<'a> TryFromCtx<'a, ChannelEncoding> for ChannelSequence {
70    type Error = scroll::Error;
71    fn try_from_ctx(
72        from: &'a [u8],
73        encoding: ChannelEncoding,
74    ) -> Result<(Self, usize), Self::Error> {
75        let mut offset = 0;
76        Ok((
77            match encoding {
78                ChannelEncoding::Simple => {
79                    ChannelSequence::Simple(from.gread::<[u8; 16]>(&mut offset)?)
80                }
81                ChannelEncoding::Legacy => ChannelSequence::Legacy({
82                    let mut array = [(LegacyFlags::default(), 0); 16];
83                    for (i, bytes) in from.gread::<[u8; 32]>(&mut offset)?.chunks(2).enumerate() {
84                        array[i] = (LegacyFlags::from_bits(bytes[0]), bytes[1]);
85                    }
86                    array
87                }),
88                ChannelEncoding::OpClass => ChannelSequence::OpClass({
89                    let mut array = [(0, 0); 16];
90                    for (i, bytes) in from.gread::<[u8; 32]>(&mut offset)?.chunks(2).enumerate() {
91                        array[i] = (bytes[0], bytes[1]);
92                    }
93                    array
94                }),
95                ChannelEncoding::Unknown(_) => {
96                    return Err(scroll::Error::BadInput {
97                        size: offset,
98                        msg: "Unknown encoding.",
99                    })
100                }
101            },
102            offset,
103        ))
104    }
105}
106impl TryIntoCtx for ChannelSequence {
107    type Error = scroll::Error;
108    fn try_into_ctx(self, buf: &mut [u8], _ctx: ()) -> Result<usize, Self::Error> {
109        match self {
110            ChannelSequence::Simple(channels) => buf.pwrite::<&[u8]>(channels.as_ref(), 0),
111            ChannelSequence::Legacy(channels) => {
112                let mut offset = 0;
113                for (flags, channel) in channels.iter() {
114                    buf.gwrite(flags.into_bits(), &mut offset)?;
115                    buf.gwrite(channel, &mut offset)?;
116                }
117                Ok(offset)
118            }
119            ChannelSequence::OpClass(channels) => {
120                let mut offset = 0;
121                for (channel, opclass) in channels.iter() {
122                    buf.gwrite(channel, &mut offset)?;
123                    buf.gwrite(opclass, &mut offset)?;
124                }
125                Ok(offset)
126            }
127        }
128    }
129}