1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use std_alloc::vec::Vec;

use super::*;
use crate::{get_size::GetSize, no_alloc::impl_to_bytes::opt_len_or_delta};

impl From<Message> for Vec<u8> {
  fn from(msg: Message) -> Vec<u8> {
    let byte1: u8 = Byte1 { tkl: msg.token.0.len() as u8,
                            ver: msg.ver,
                            ty: msg.ty }.into();
    let code: u8 = msg.code.into();
    let id: [u8; 2] = msg.id.into();

    let size = msg.get_size();
    let mut bytes = Vec::<u8>::with_capacity(size);

    bytes.push(byte1);
    bytes.push(code);
    bytes.extend(id);
    bytes.extend(msg.token.0);
    msg.opts.into_iter().for_each(|o| o.extend_bytes(&mut bytes));
    if !msg.payload.0.is_empty() {
      bytes.push(0b11111111);
      bytes.extend(msg.payload.0);
    }

    bytes
  }
}

impl Opt {
  fn extend_bytes(self, bytes: &mut impl Extend<u8>) {
    let (del, del_bytes) = opt_len_or_delta(self.delta.0);
    let (len, len_bytes) = opt_len_or_delta(self.value.0.len() as u16);
    let del = del << 4;

    let header = del | len;

    bytes.extend(core::iter::once(header));
    if let Some(del_bytes) = del_bytes {
      bytes.extend(del_bytes);
    }
    if let Some(len_bytes) = len_bytes {
      bytes.extend(len_bytes);
    }

    bytes.extend(self.value.0);
  }
}

impl From<Opt> for Vec<u8> {
  fn from(opt: Opt) -> Vec<u8> {
    let mut bytes = Vec::<u8>::with_capacity(opt.get_size());
    opt.extend_bytes(&mut bytes);
    bytes
  }
}

#[cfg(test)]
mod tests {
  use super::*;

  macro_rules! assert_eqb_iter {
    ($actual:expr, $expected:expr) => {
      if $actual.iter().ne($expected.iter()) {
        panic!("expected {:?} to equal {:?}",
               $actual.into_iter().map(|b| format!("{:08b}", b)).collect::<Vec<_>>(),
               $expected.into_iter().map(|b| format!("{:08b}", b)).collect::<Vec<_>>())
      }
    };
  }

  #[test]
  fn msg() {
    let (m, expected) = super::super::test_msg();
    let actual: Vec<u8> = m.into();
    assert_eqb_iter!(actual, expected);
  }

  #[test]
  fn opt() {
    use core::iter::repeat;
    let cases: [(u16, Vec<u8>, Vec<u8>); 4] = [(24,
                                                repeat(1).take(100).collect(),
                                                [[0b1101_1101u8, 24 - 13, 100 - 13].as_ref(),
                                                 repeat(1).take(100).collect::<Vec<u8>>().as_ref()].concat()),
                                               (1, vec![1], vec![0b0001_0001, 1]),
                                               (24, vec![1], vec![0b1101_0001, 11, 1]),
                                               (24,
                                                repeat(1).take(300).collect(),
                                                [[0b1101_1110, 24 - 13].as_ref(),
                                                 (300u16 - 269).to_be_bytes().as_ref(),
                                                 repeat(1).take(300).collect::<Vec<u8>>().as_ref()].concat())];

    cases.into_iter().for_each(|(delta, values, expected)| {
                       let opt = Opt { delta: OptDelta(delta),
                                       value: OptValue(values.into_iter().collect()) };
                       let actual: Vec<u8> = opt.into();
                       assert_eqb_iter!(actual, expected)
                     });
  }

  #[test]
  fn no_payload_marker() {
    let msg = Message { id: Id(0),
                        ty: Type(0),
                        ver: Default::default(),
                        code: Code { class: 2, detail: 5 },
                        token: Token(Default::default()),
                        opts: Default::default(),
                        payload: Payload(Default::default()) };

    assert_ne!(Vec::<u8>::from(msg).last(), Some(&0b11111111));
  }
}