minicbor/
lib.rs

1//! A small [CBOR] codec suitable for `no_std` environments.
2//!
3//! The crate is organised around the following entities:
4//!
5//! - [`Encoder`] and [`Decoder`] for type-directed encoding and decoding
6//!   of values.
7//!
8//! - [`Encode`] and [`Decode`] traits which can be implemented for any
9//!   type that should be encoded to or decoded from CBOR. They are similar
10//!   to [serde]'s `Serialize` and `Deserialize` traits but do not abstract
11//!   over the encoder/decoder.
12//!
13//! Encoding and decoding proceeds in a type-directed way, i.e.  by calling
14//! methods for expected data item types, e.g. [`Decoder::u32`] or
15//! [`Encoder::str`]. In addition there is support for data type inspection.
16//! The `Decoder` can be queried for the current data type which returns a
17//! [`data::Type`] that can represent every possible CBOR type and decoding
18//! can thus proceed based on this information. It is also possible to just
19//! tokenize the input bytes using a [`Tokenizer`](decode::Tokenizer), i.e.
20//! an `Iterator` over CBOR [`Token`](data::Token)s. Finally, the length
21//! in bytes of a value's CBOR representation can be calculated if the
22//! value's type implements the [`CborLen`] trait.
23//!
24//! Optionally, `Encode` and `Decode` can be derived for structs and enums
25//! using the respective derive macros (*requires feature* `"derive"`).
26//! See [`minicbor_derive`] for details.
27//!
28//! For I/O support see [`minicbor-io`][1].
29//!
30//! Support for [serde][2] is available in [`minicbor-serde`][3].
31//!
32//! [1]: https://docs.rs/minicbor_io/
33//! [2]: https://crates.io/crates/serde
34//! [3]: https://crates.io/crates/minicbor-serde
35//!
36//! # Feature flags
37//!
38//! The following feature flags are supported:
39//!
40//! - `"alloc"`: Enables most collection types in a `no_std` environment.
41//!
42//! - `"std"`: Implies `"alloc"` and enables more functionality that depends
43//!   on the `std` crate.
44//!
45//! - `"derive"`: Allows deriving [`Encode`] and [`Decode`] traits.
46//!
47//! # Example: generic encoding and decoding
48//!
49//! ```
50//! use minicbor::{Encode, Decode};
51//!
52//! let input = ["hello", "world"];
53//! let mut buffer = [0u8; 128];
54//!
55//! minicbor::encode(&input, buffer.as_mut())?;
56//! let output: [&str; 2] = minicbor::decode(buffer.as_ref())?;
57//! assert_eq!(input, output);
58//!
59//! # Ok::<_, Box<dyn core::error::Error>>(())
60//! ```
61//!
62//! # Example: ad-hoc encoding
63//!
64//! ```
65//! use minicbor::Encoder;
66//!
67//! let mut buffer = [0u8; 128];
68//! let mut encoder = Encoder::new(&mut buffer[..]);
69//!
70//! encoder.begin_map()? // using an indefinite map here
71//!     .str("hello")?.str("world")?
72//!     .str("submap")?.map(2)?
73//!         .u8(1)?.bool(true)?
74//!         .u8(2)?.bool(false)?
75//!     .u16(34234)?.array(3)?.u8(1)?.u8(2)?.u8(3)?
76//!     .bool(true)?.null()?
77//! .end()?;
78//!
79//! # Ok::<_, Box<dyn core::error::Error>>(())
80//! ```
81//!
82//! # Example: ad-hoc decoding
83//!
84//! ```
85//! use minicbor::Decoder;
86//! use minicbor::data::IanaTag;
87//!
88//! let input = [
89//!     0xc0, 0x74, 0x32, 0x30, 0x31, 0x33, 0x2d, 0x30,
90//!     0x33, 0x2d, 0x32, 0x31, 0x54, 0x32, 0x30, 0x3a,
91//!     0x30, 0x34, 0x3a, 0x30, 0x30, 0x5a
92//! ];
93//!
94//! let mut decoder = Decoder::new(&input);
95//! assert_eq!(IanaTag::DateTime.tag(), decoder.tag()?);
96//! assert_eq!("2013-03-21T20:04:00Z", decoder.str()?);
97//! # Ok::<_, Box<dyn core::error::Error>>(())
98//! ```
99//!
100//! # Example: tokenization
101//!
102//! ```
103//! use minicbor::display;
104//! use minicbor::{Encoder, Decoder};
105//! use minicbor::data::Token;
106//!
107//! let input  = [0x83, 0x01, 0x9f, 0x02, 0x03, 0xff, 0x82, 0x04, 0x05];
108//!
109//! assert_eq!("[1, [_ 2, 3], [4, 5]]", format!("{}", display(&input)));
110//!
111//! let tokens = Decoder::new(&input).tokens().collect::<Result<Vec<Token>, _>>()?;
112//!
113//! assert_eq! { &tokens[..],
114//!     &[Token::Array(3),
115//!       Token::U8(1),
116//!       Token::BeginArray,
117//!       Token::U8(2),
118//!       Token::U8(3),
119//!       Token::Break,
120//!       Token::Array(2),
121//!       Token::U8(4),
122//!       Token::U8(5)]
123//! };
124//!
125//! let mut buffer = [0u8; 9];
126//! Encoder::new(buffer.as_mut()).tokens(&tokens)?;
127//!
128//! assert_eq!(input, buffer);
129//!
130//! # Ok::<_, Box<dyn core::error::Error>>(())
131//! ```
132//!
133//! [CBOR]: https://datatracker.ietf.org/doc/html/rfc8949
134//! [serde]: https://serde.rs
135
136#![forbid(unused_variables)]
137#![allow(clippy::needless_lifetimes)]
138#![cfg_attr(not(feature = "std"), no_std)]
139
140#[cfg(feature = "alloc")]
141extern crate alloc;
142
143pub mod bytes;
144pub mod data;
145pub mod decode;
146pub mod encode;
147
148const UNSIGNED: u8 = 0x00;
149const SIGNED: u8   = 0x20;
150const BYTES: u8    = 0x40;
151const TEXT: u8     = 0x60;
152const ARRAY: u8    = 0x80;
153const MAP: u8      = 0xa0;
154const TAGGED: u8   = 0xc0;
155const SIMPLE: u8   = 0xe0;
156const BREAK: u8    = 0xff;
157
158pub use decode::{Decode, Decoder};
159pub use encode::{Encode, Encoder, CborLen};
160
161#[cfg(feature = "derive")]
162pub use minicbor_derive::*;
163
164#[cfg(feature = "alloc")]
165use core::convert::Infallible;
166
167#[cfg(feature = "alloc")]
168use alloc::vec::Vec;
169
170/// Decode a type implementing [`Decode`] from the given byte slice.
171pub fn decode<'b, T>(b: &'b [u8]) -> Result<T, decode::Error>
172where
173    T: Decode<'b, ()>
174{
175    Decoder::new(b).decode()
176}
177
178/// Decode a type implementing [`Decode`] from the given byte slice.
179pub fn decode_with<'b, C, T>(b: &'b [u8], ctx: &mut C) -> Result<T, decode::Error>
180where
181    T: Decode<'b, C>
182{
183    Decoder::new(b).decode_with(ctx)
184}
185
186/// Encode a type implementing [`Encode`] to the given [`encode::Write`] impl.
187pub fn encode<T, W>(x: T, w: W) -> Result<(), encode::Error<W::Error>>
188where
189    T: Encode<()>,
190    W: encode::Write
191{
192    Encoder::new(w).encode(x)?.ok()
193}
194
195/// Encode a type implementing [`Encode`] to the given [`encode::Write`] impl.
196pub fn encode_with<C, T, W>(x: T, w: W, ctx: &mut C) -> Result<(), encode::Error<W::Error>>
197where
198    T: Encode<C>,
199    W: encode::Write
200{
201    Encoder::new(w).encode_with(x, ctx)?.ok()
202}
203
204/// Encode a type implementing [`Encode`] and return the encoded byte vector.
205///
206/// *Requires feature* `"alloc"`.
207#[cfg(feature = "alloc")]
208pub fn to_vec<T>(x: T) -> Result<Vec<u8>, encode::Error<Infallible>>
209where
210    T: Encode<()>
211{
212    let mut e = Encoder::new(Vec::new());
213    x.encode(&mut e, &mut ())?;
214    Ok(e.into_writer())
215}
216
217/// Encode a type implementing [`Encode`] and return the encoded byte vector.
218///
219/// *Requires feature* `"alloc"`.
220#[cfg(feature = "alloc")]
221pub fn to_vec_with<C, T>(x: T, ctx: &mut C) -> Result<Vec<u8>, encode::Error<Infallible>>
222where
223    T: Encode<C>
224{
225    let mut e = Encoder::new(Vec::new());
226    x.encode(&mut e, ctx)?;
227    Ok(e.into_writer())
228}
229
230/// Display the given CBOR bytes in [diagnostic notation][1].
231///
232/// *Requires features* `"alloc"` *and* `"half"`.
233///
234/// Quick syntax summary:
235///
236/// - Maps are enclosed in curly braces: `{` and `}`.
237/// - Arrays are enclosed in brackets: `[` and `]`.
238/// - Indefinite maps start with `{_` instead of `{`.
239/// - Indefinite arrays start with `[_` instead of `[`.
240/// - Bytes are hex encoded and enclosed in `h'` and `'`.
241/// - Strings are enclosed in double quotes.
242/// - Numbers and booleans are displayed as in Rust but floats are always
243///   shown in scientific notation (this differs slightly from the RFC
244///   format).
245/// - Indefinite bytes are enclosed in `(_` and `)` except for the empty
246///   sequence which is shown as `''_`.
247/// - Indefinite strings are enclosed in `(_` and `)` except for the empty
248///   sequence which is shown as `""_`.
249/// - Tagged values are enclosed in `t(` and `)` where `t` is the numeric
250///   tag value.
251/// - Simple values are shown as `simple(n)` where `n` is the numeric
252///   simple value.
253/// - Undefined and null are shown as `undefined` and `null`.
254///
255/// No error is produced should decoding fail, the error message
256/// becomes part of the display.
257///
258/// [1]: https://www.rfc-editor.org/rfc/rfc8949.html#section-8
259#[cfg(all(feature = "alloc", feature = "half"))]
260pub fn display<'b>(cbor: &'b [u8]) -> impl core::fmt::Display + 'b {
261    decode::Tokenizer::new(cbor)
262}
263
264/// Calculate the length in bytes of the given value's CBOR representation.
265pub fn len<T>(x: T) -> usize
266where
267    T: CborLen<()>
268{
269    x.cbor_len(&mut ())
270}
271
272/// Calculate the length in bytes of the given value's CBOR representation.
273pub fn len_with<C, T>(x: T, ctx: &mut C) -> usize
274where
275    T: CborLen<C>
276{
277    x.cbor_len(ctx)
278}
279
280// Ensure we can safely cast a `usize` to a `u64`.
281const __USIZE_FITS_INTO_U64: () =
282    assert!(core::mem::size_of::<usize>() <= core::mem::size_of::<u64>());