toad_msg/
to_bytes.rs

1use tinyvec::ArrayVec;
2use toad_len::Len;
3
4use crate::*;
5
6/// Trait allowing fallible conversion into bytes
7pub trait TryIntoBytes {
8  type Error;
9
10  /// Try to convert into a collection of bytes
11  ///
12  /// ```
13  /// use tinyvec::ArrayVec;
14  /// use toad_msg::{Message, OptNumber, OptValue, TryIntoBytes};
15  ///
16  /// type OptionValue = OptValue<ArrayVec<[u8; 128]>>;
17  /// type OptionMapEntry = (OptNumber, ArrayVec<[OptionValue; 4]>);
18  /// type OptionMap = ArrayVec<[OptionMapEntry; 16]>;
19  /// type Payload = ArrayVec<[u8; 1024]>;
20  /// let arrayvec_message = Message::<Payload, OptionMap> {
21  ///   // ...
22  /// # id: toad_msg::Id(0),
23  /// # ty: toad_msg::Type::Con,
24  /// # ver: Default::default(),
25  /// # opts: Default::default(),
26  /// # payload: toad_msg::Payload(Default::default()),
27  /// # token: toad_msg::Token(Default::default()),
28  /// # code: toad_msg::Code {class: 0, detail: 1},
29  /// };
30  ///
31  /// let bytes: tinyvec::ArrayVec<[u8; 1024]> = arrayvec_message.try_into_bytes().unwrap();
32  ///
33  /// // This one uses Vec
34  /// let vec_message = toad_msg::alloc::Message {
35  ///   // ...
36  /// # id: toad_msg::Id(0),
37  /// # ty: toad_msg::Type::Con,
38  /// # ver: Default::default(),
39  /// # opts: Default::default(),
40  /// # payload: toad_msg::Payload(Default::default()),
41  /// # token: toad_msg::Token(Default::default()),
42  /// # code: toad_msg::Code {class: 0, detail: 1},
43  /// };
44  ///
45  /// let bytes: Vec<u8> = vec_message.try_into_bytes().unwrap();
46  /// ```
47  fn try_into_bytes<C: Array<Item = u8>>(self) -> Result<C, Self::Error>;
48}
49
50/// Errors encounterable serializing to bytes
51#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
52pub enum MessageToBytesError {
53  /// Reserved capacity was not enough for size of message
54  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}