1use crate::error::Error;
11use alloc::vec::Vec;
12
13#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct Raw {
16 pub reader: u8,
18 pub format_code: u8,
20 pub bit_count: u16,
22 pub bits: Vec<u8>,
24}
25
26impl Raw {
27 pub fn encode(&self) -> Result<Vec<u8>, Error> {
29 let need = (self.bit_count as usize).div_ceil(8);
30 if self.bits.len() != need {
31 return Err(Error::MalformedPayload {
32 code: 0x50,
33 reason: "RAW bit count does not match byte length",
34 });
35 }
36 let mut out = Vec::with_capacity(4 + self.bits.len());
37 out.push(self.reader);
38 out.push(self.format_code);
39 out.extend_from_slice(&self.bit_count.to_le_bytes());
40 out.extend_from_slice(&self.bits);
41 Ok(out)
42 }
43
44 pub fn decode(data: &[u8]) -> Result<Self, Error> {
46 if data.len() < 4 {
47 return Err(Error::MalformedPayload {
48 code: 0x50,
49 reason: "RAW requires at least 4 bytes",
50 });
51 }
52 let bit_count = u16::from_le_bytes([data[2], data[3]]);
53 let need = (bit_count as usize).div_ceil(8);
54 if data.len() != 4 + need {
55 return Err(Error::MalformedPayload {
56 code: 0x50,
57 reason: "RAW bit count does not match payload length",
58 });
59 }
60 Ok(Self {
61 reader: data[0],
62 format_code: data[1],
63 bit_count,
64 bits: data[4..].to_vec(),
65 })
66 }
67
68 pub fn iter_bits(&self) -> impl Iterator<Item = bool> + '_ {
71 let n = self.bit_count as usize;
72 self.bits
73 .iter()
74 .enumerate()
75 .flat_map(move |(byte_idx, &b)| {
76 (0..8).filter_map(move |bit| {
77 let pos = byte_idx * 8 + bit;
78 if pos >= n {
79 None
80 } else {
81 Some(b & (0x80 >> bit) != 0)
82 }
83 })
84 })
85 }
86}
87
88#[derive(Debug, Clone, PartialEq, Eq)]
90pub struct Fmt {
91 pub reader: u8,
93 pub direction: u8,
95 pub char_count: u8,
97 pub chars: Vec<u8>,
99}
100
101impl Fmt {
102 pub fn encode(&self) -> Result<Vec<u8>, Error> {
104 if self.chars.len() != self.char_count as usize {
105 return Err(Error::MalformedPayload {
106 code: 0x51,
107 reason: "FMT char_count disagrees with chars",
108 });
109 }
110 let mut out = Vec::with_capacity(3 + self.chars.len());
111 out.push(self.reader);
112 out.push(self.direction);
113 out.push(self.char_count);
114 out.extend_from_slice(&self.chars);
115 Ok(out)
116 }
117
118 pub fn decode(data: &[u8]) -> Result<Self, Error> {
120 if data.len() < 3 {
121 return Err(Error::MalformedPayload {
122 code: 0x51,
123 reason: "FMT requires at least 3 bytes",
124 });
125 }
126 let char_count = data[2];
127 if data.len() != 3 + char_count as usize {
128 return Err(Error::MalformedPayload {
129 code: 0x51,
130 reason: "FMT char_count disagrees with payload",
131 });
132 }
133 Ok(Self {
134 reader: data[0],
135 direction: data[1],
136 char_count,
137 chars: data[3..].to_vec(),
138 })
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 #[test]
147 fn raw_iter_bits_truncates() {
148 let raw = Raw {
150 reader: 0,
151 format_code: 0,
152 bit_count: 26,
153 bits: alloc::vec![0xAA, 0xBB, 0xCC, 0x80],
154 };
155 let bits: alloc::vec::Vec<bool> = raw.iter_bits().collect();
156 assert_eq!(bits.len(), 26);
157 }
158
159 #[test]
160 fn raw_roundtrip() {
161 let r = Raw {
162 reader: 1,
163 format_code: 0,
164 bit_count: 26,
165 bits: alloc::vec![0xAA, 0xBB, 0xCC, 0x80],
166 };
167 let bytes = r.encode().unwrap();
168 let parsed = Raw::decode(&bytes).unwrap();
169 assert_eq!(parsed, r);
170 }
171}