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<_>>())
}
};
}
}