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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//! Low-level representation of CoAP messages.
//!
//! The most notable item in `toad_msg` is `Message`;
//! a CoAP message very close to the actual byte layout.
//!
//! ## Allocation
//! CoAP messages are growable and dynamically sized:
//! - The message payload (_http equiv_: the request/response body)
//! - the number of options (_http equiv_: headers)
//! - the value of an option (_http equiv_: header value)
//!
//! ## Performance
//! This crate uses `criterion` to measure performance of the heaped & heapless implementations in this crate as well as `coap_lite::Packet`.
//!
//! In general, `toad_msg::VecMessage` performs identically to coap_lite (+/- 5%), and both are **much** faster than `toad_msg::ArrayVecMessage`.
//!
//! Benchmarks:
//! ### Serializing to bytes
//! <details>
//! <summary>
//!
//! **Click to expand chart**
//! </summary>
//!
//! ![chart](https://raw.githubusercontent.com/clov-coffee/toad/main/toad-msg/docs/from_bytes.svg)
//! </details>
//!
//! ### Deserializing from bytes
//! <details>
//! <summary>
//!
//! **Click to expand chart**
//! </summary>
//!
//! ![chart](https://raw.githubusercontent.com/clov-coffee/toad/main/toad-msg/docs/to_bytes.svg)
//! </details>

// x-release-please-start-version
#![doc(html_root_url = "https://docs.rs/toad-msg/0.19.0")]
// x-release-please-end
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(test), forbid(missing_debug_implementations, unreachable_pub))]
#![cfg_attr(not(test), deny(unsafe_code, missing_copy_implementations))]
#![cfg_attr(any(docsrs, feature = "docs"), feature(doc_cfg))]
#![deny(missing_docs)]

#[cfg(feature = "alloc")]
extern crate alloc as std_alloc;

#[doc(hidden)]
pub mod from_bytes;

#[allow(missing_docs)]
pub mod cache_key;

/// Message structs
pub mod msg;

#[doc(hidden)]
pub mod to_bytes;

#[doc(inline)]
pub use cache_key::*;
#[doc(inline)]
pub use from_bytes::TryFromBytes;
#[doc(inline)]
pub use msg::*;
#[doc(inline)]
pub use to_bytes::TryIntoBytes;
use toad_array::Array;

/// Type aliases for std or alloc platforms
#[cfg(feature = "alloc")]
pub mod alloc {
  use std_alloc::collections::BTreeMap;
  use std_alloc::vec::Vec;

  use crate::{OptNumber, OptValue};

  /// [`crate::Message`] that uses Vec and BTreeMap
  pub type Message = crate::Message<Vec<u8>, BTreeMap<OptNumber, Vec<OptValue<Vec<u8>>>>>;

  /// [`crate::MessageBuilder`] that uses Vec and BTreeMap
  pub type MessageBuilder =
    crate::MessageBuilder<Vec<u8>, BTreeMap<OptNumber, Vec<OptValue<Vec<u8>>>>>;
}

#[cfg(test)]
pub(crate) fn test_msg() -> (alloc::Message, Vec<u8>) {
  use std_alloc::collections::BTreeMap;
  // TEST

  let header: [u8; 4] = 0b0100_0001_0100_0101_0000_0000_0000_0001_u32.to_be_bytes();
  let token: [u8; 1] = [254u8];
  let content_format: &[u8] = b"application/json";
  let options: [&[u8]; 2] = [&[0b_1100_1101u8, 0b00000011u8], content_format];
  let payload: [&[u8]; 2] = [&[0b1111_1111_u8], b"hello, world!"];
  let bytes = [header.as_ref(),
               token.as_ref(),
               options.concat().as_ref(),
               payload.concat().as_ref()].concat();

  let msg = alloc::Message { id: Id(1),
                             ty: Type::Con,
                             ver: Version(1),
                             token: Token(tinyvec::array_vec!([u8; 8] => 254)),
                             opts: BTreeMap::from([(OptNumber(12),
                                                    vec![OptValue(content_format.to_vec())])]),
                             code: Code { class: 2,
                                          detail: 5 },
                             payload: Payload(b"hello, world!".to_vec()) };
  (msg, bytes)
}

#[cfg(test)]
pub(crate) mod tests {
  #[macro_export]
  macro_rules! assert_eqb {
    ($actual:expr, $expected:expr) => {
      if $actual != $expected {
        panic!("expected {:08b} to equal {:08b}", $actual, $expected)
      }
    };
  }

  #[macro_export]
  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<_>>())
      }
    };
  }
}