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