1use tinyvec::ArrayVec;
2use toad_len::Len;
3
4use crate::*;
5
6pub trait TryIntoBytes {
8 type Error;
9
10 fn try_into_bytes<C: Array<Item = u8>>(self) -> Result<C, Self::Error>;
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
52pub enum MessageToBytesError {
53 TooLong { capacity: usize, size: usize },
55}
56
57impl<PayloadBytes: Array<Item = u8>, Options: OptionMap> TryIntoBytes
58 for Message<PayloadBytes, Options>
59{
60 type Error = MessageToBytesError;
61
62 fn try_into_bytes<C: Array<Item = u8>>(self) -> Result<C, Self::Error> {
63 let mut bytes = C::reserve(self.len());
64 let size: usize = self.len();
65
66 if let Some(max) = C::CAPACITY {
67 if max < size {
68 return Err(Self::Error::TooLong { capacity: max,
69 size });
70 }
71 }
72
73 let byte1: u8 = Byte1 { tkl: self.token.0.len() as u8,
74 ver: self.ver,
75 ty: self.ty }.into();
76 let code: u8 = self.code.into();
77 let id: [u8; 2] = self.id.into();
78 let token: ArrayVec<[u8; 8]> = self.token.0;
79
80 bytes.extend(Some(byte1));
81 bytes.extend(Some(code));
82
83 bytes.extend(id);
84 bytes.extend(token);
85
86 for opt in self.opts.opts() {
87 opt.extend_bytes(&mut bytes);
88 }
89
90 if !self.payload.0.is_empty() {
91 bytes.extend(Some(0b11111111));
92 bytes.extend(self.payload.0);
93 }
94
95 Ok(bytes)
96 }
97}
98
99pub(crate) fn opt_len_or_delta(val: u16) -> (u8, Option<ArrayVec<[u8; 2]>>) {
100 match val {
101 | n if n >= 269 => {
102 let mut bytes = ArrayVec::new();
103 bytes.extend((n - 269).to_be_bytes());
104 (14, Some(bytes))
105 },
106 | n if n >= 13 => {
107 let mut bytes = ArrayVec::new();
108 bytes.push((n as u8) - 13);
109 (13, Some(bytes))
110 },
111 | n => (n as u8, None),
112 }
113}
114
115impl From<Id> for [u8; 2] {
116 fn from(id: Id) -> [u8; 2] {
117 id.0.to_be_bytes()
118 }
119}
120
121impl From<Type> for u8 {
122 fn from(t: Type) -> u8 {
123 use Type::*;
124 match t {
125 | Con => 0,
126 | Non => 1,
127 | Ack => 2,
128 | Reset => 3,
129 }
130 }
131}
132
133impl From<Byte1> for u8 {
134 fn from(b: Byte1) -> u8 {
135 let ver = b.ver.0 << 6;
136 let ty = u8::from(b.ty) << 4;
137 let tkl = b.tkl;
138
139 ver | ty | tkl
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146
147 macro_rules! assert_eqb {
148 ($actual:expr, $expected:expr) => {
149 if $actual != $expected {
150 panic!("expected {:08b} to equal {:08b}", $actual, $expected)
151 }
152 };
153 }
154
155 macro_rules! assert_eqb_iter {
156 ($actual:expr, $expected:expr) => {
157 if $actual.iter().ne($expected.iter()) {
158 panic!("expected {:?} to equal {:?}",
159 $actual.into_iter()
160 .map(|b| format!("{:08b}", b))
161 .collect::<Vec<_>>(),
162 $expected.into_iter()
163 .map(|b| format!("{:08b}", b))
164 .collect::<Vec<_>>())
165 }
166 };
167 }
168
169 #[test]
170 fn msg() {
171 let (msg, expected) = test_msg();
172 let actual: Vec<u8> = msg.try_into_bytes().unwrap();
173 assert_eqb_iter!(actual, expected);
174 }
175
176 #[test]
177 fn byte_1() {
178 let byte = Byte1 { ver: Version(1),
179 ty: Type::Ack,
180 tkl: 3 };
181 let actual: u8 = byte.into();
182 let expected = 0b_01_10_0011u8;
183 assert_eqb!(actual, expected)
184 }
185
186 #[test]
187 fn code() {
188 let code = Code { class: 2,
189 detail: 5 };
190 let actual: u8 = code.into();
191 let expected = 0b0100_0101_u8;
192 assert_eqb!(actual, expected)
193 }
194
195 #[test]
196 fn id() {
197 let id = Id(16);
198 let actual = u16::from_be_bytes(id.into());
199 assert_eqb!(actual, 16)
200 }
201
202 #[test]
203 fn opt() {
204 use core::iter::repeat;
205 let cases: [(u16, Vec<u8>, Vec<u8>); 4] =
206 [(24,
207 repeat(1).take(100).collect(),
208 [[0b1101_1101u8, 24 - 13, 100 - 13].as_ref(),
209 repeat(1).take(100).collect::<Vec<u8>>().as_ref()].concat()),
210 (1, vec![1], vec![0b0001_0001, 1]),
211 (24, vec![1], vec![0b1101_0001, 11, 1]),
212 (24,
213 repeat(1).take(300).collect(),
214 [[0b1101_1110, 24 - 13].as_ref(),
215 (300u16 - 269).to_be_bytes().as_ref(),
216 repeat(1).take(300).collect::<Vec<u8>>().as_ref()].concat())];
217
218 cases.into_iter().for_each(|(delta, values, expected)| {
219 let opt = Opt::<Vec<u8>> { delta: OptDelta(delta),
220 value: OptValue(values.into_iter().collect()) };
221 let mut actual = Vec::<u8>::new();
222 opt.extend_bytes(&mut actual);
223 assert_eqb_iter!(actual, expected)
224 });
225 }
226
227 #[test]
228 fn no_payload_marker() {
229 let msg = alloc::Message { id: Id(0),
230 ty: Type::Con,
231 ver: Default::default(),
232 code: Code { class: 2,
233 detail: 5 },
234 token: Token(Default::default()),
235 opts: Default::default(),
236 payload: Payload(Default::default()) };
237
238 assert_ne!(msg.try_into_bytes::<Vec<_>>().unwrap().last(),
239 Some(&0b11111111));
240 }
241}