cbor_core/lib.rs
1#![forbid(unsafe_code)]
2#![deny(rustdoc::broken_intra_doc_links)]
3#![deny(rustdoc::private_intra_doc_links)]
4#![cfg_attr(docsrs, feature(doc_cfg))]
5
6//! Deterministic CBOR encoder and decoder following the
7//! [CBOR::Core](https://www.ietf.org/archive/id/draft-rundgren-cbor-core-25.html)
8//! profile (`draft-rundgren-cbor-core-25`). Encoding produces the
9//! canonical form; the decoder rejects input that deviates, with opt-in
10//! normalization for non-canonical sources.
11//!
12//! The central type is [`Value`]. It can be constructed, inspected,
13//! modified in place, encoded to bytes, and decoded back. The API
14//! follows CBOR's own shape, so tagged values, simple values, and
15//! arbitrary map keys stay directly reachable.
16//! [`Value`] carries a lifetime parameter so that decoded text and
17//! byte strings can borrow zero-copy from the input slice.
18//!
19//! # Types
20//!
21//! Auxiliary types, grouped by role:
22//!
23//! * [`Array`], [`Map`], [`Float`], [`DateTime`], [`EpochTime`], and
24//! [`SimpleValue`] appear in `From`/`Into` bounds for `Value` and are
25//! rarely constructed by hand.
26//! * [`DataType`] reports a value's kind for type-based dispatch.
27//! [`ValueKey`] is the key type for maps.
28//! * [`DecodeOptions`] configures the decoder and [`Format`] selects
29//! binary, hex, or diagnostic input. [`SequenceDecoder`] and
30//! [`SequenceReader`] iterate over CBOR sequences; [`SequenceWriter`]
31//! is their encode-side counterpart, configured with [`EncodeFormat`].
32//! * [`Error`] and [`Result`] cover in-memory decoding; [`IoError`] and
33//! [`IoResult`] cover `io::Read` sources.
34//!
35//! # Quick start
36//!
37//! ```
38//! use cbor_core::{Value, array, map};
39//!
40//! // Build a value
41//! let value = map! {
42//! 1 => "hello",
43//! 2 => array![10, 20, 30],
44//! };
45//!
46//! // Encode to bytes and decode back
47//! let bytes = value.encode();
48//! let decoded = Value::decode(&bytes).unwrap();
49//! assert_eq!(value, decoded);
50//!
51//! // Access inner data
52//! let greeting = decoded[1].as_str().unwrap();
53//! assert_eq!(greeting, "hello");
54//!
55//! // Round-trip through diagnostic notation
56//! let text = format!("{value:?}");
57//! let parsed: Value = text.parse().unwrap();
58//! assert_eq!(value, parsed);
59//! ```
60//!
61//! # Diagnostic notation
62//!
63//! [`Value`] implements [`FromStr`](std::str::FromStr), so any CBOR value can
64//! be written as text and parsed with `str::parse`.
65//!
66//! The grammar is Section 2.3.6 of the CBOR::Core draft. Examples:
67//!
68//! ```
69//! use cbor_core::Value;
70//!
71//! // Integers in any base, with `_` as a digit separator
72//! let v: Value = "0xff_ff_00_00".parse().unwrap();
73//! assert_eq!(v, Value::from(0xff_ff_00_00_u32));
74//!
75//! // Arbitrary precision: parsed as tag 2 / tag 3 big integers
76//! let big: Value = "18446744073709551616".parse().unwrap();
77//! assert_eq!(big, Value::from(u64::MAX as u128 + 1));
78//!
79//! // Floats, including explicit bit patterns for NaN payloads
80//! let f: Value = "1.5e2".parse().unwrap();
81//! assert_eq!(f, Value::from(150.0));
82//! let nan: Value = "float'7f800001'".parse().unwrap();
83//! assert_eq!(nan.encode(), vec![0xfa, 0x7f, 0x80, 0x00, 0x01]);
84//!
85//! // Byte strings: hex, base64, ASCII, or embedded CBOR
86//! assert_eq!("h'48656c6c6f'".parse::<Value>().unwrap(), Value::from(b"Hello".to_vec()));
87//! assert_eq!("b64'SGVsbG8'".parse::<Value>().unwrap(), Value::from(b"Hello".to_vec()));
88//! assert_eq!("'Hello'".parse::<Value>().unwrap(), Value::from(b"Hello".to_vec()));
89//! // << ... >> wraps a CBOR sequence into a byte string
90//! assert_eq!(
91//! "<< 1, 2, 3 >>".parse::<Value>().unwrap(),
92//! Value::from(vec![0x01, 0x02, 0x03]),
93//! );
94//! ```
95//!
96//! Nested structures are written directly, and maps may appear in any
97//! order. The parser sorts keys and rejects duplicates:
98//!
99//! ```
100//! use cbor_core::Value;
101//!
102//! let cert: Value = r#"{
103//! / CWT-style claims, written out of canonical order /
104//! "iss": "https://issuer.example",
105//! "sub": "user-42",
106//! "iat": 1700000000,
107//! "cnf": {
108//! "kty": "OKP",
109//! "crv": "Ed25519",
110//! "x": h'd75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a'
111//! },
112//! "scope": ["read", "write"]
113//! }"#.parse().unwrap();
114//!
115//! assert_eq!(cert["sub"].as_str().unwrap(), "user-42");
116//! assert_eq!(cert["cnf"]["crv"].as_str().unwrap(), "Ed25519");
117//! ```
118//!
119//! Supported grammar elements:
120//!
121//! * arbitrary-precision integers in any base (`0x`, `0o`, `0b`, decimal),
122//! with `_` separators
123//! * floats: decimal, scientific, `NaN`, `Infinity`, or `float'<hex>'` for
124//! explicit bit patterns
125//! * text strings with JSON-style escapes and surrogate pairs
126//! * byte strings: `h'...'`, `b64'...'`, `'...'`, or `<<...>>` for embedded
127//! CBOR
128//! * arrays, maps, tagged values (`N(...)`), simple values (`simple(N)`,
129//! `true`, `false`, `null`)
130//! * comments: single-line `# ...` and block `/ ... /`
131//!
132//! The parser accepts non-canonical input (for example unsorted maps and
133//! non-shortest numbers), normalizes it, and produces a canonical [`Value`].
134//! Round-tripping `format!("{v:?}").parse::<Value>()` always yields the
135//! original value.
136//!
137//! # Borrowing and ownership
138//!
139//! [`Value`] carries a lifetime parameter so that text and byte
140//! strings can either own their storage or borrow it. The variants
141//! that hold strings are
142//! [`TextString(Cow<'a, str>)`](Value::TextString) and
143//! [`ByteString(Cow<'a, [u8]>)`](Value::ByteString).
144//!
145//! Decoding binary CBOR from a byte slice is zero-copy: each text
146//! and byte string in the result is a `Cow::Borrowed` pointing into
147//! the input slice. The returned value's lifetime is the slice's
148//! lifetime:
149//!
150//! ```
151//! use cbor_core::Value;
152//!
153//! let bytes: &[u8] = b"\x65hello"; // text string "hello"
154//! let v = Value::decode(bytes).unwrap();
155//! assert_eq!(v.as_str().unwrap(), "hello");
156//! // `v` borrows from `bytes`; dropping `bytes` would be a borrow error.
157//! ```
158//!
159//! Hex decoding ([`Value::decode_hex`]) and stream decoding from any
160//! [`io::Read`](std::io::Read) source ([`Value::read_from`],
161//! [`SequenceReader`]) cannot borrow: hex pairs have to be decoded
162//! into bytes, and a stream is read into an internal buffer. Those
163//! paths always produce an owned `Value<'static>`.
164//!
165//! Values built in code follow the same split: passing an owned
166//! `String`, `Vec<u8>`, integer, float, etc. produces an owned
167//! `Value<'static>`, while passing a reference (`&str`, `&[u8]`,
168//! `&[u8; N]`) produces a `Value<'a>` borrowing from that reference.
169//! A `&'static str` literal yields `Value<'static>`. The
170//! [`array!`](crate::array) and [`map!`](crate::map) macros and the
171//! `From`/`TryFrom` conversions follow whatever the element type
172//! does.
173//!
174//! `Value` is covariant in its lifetime, so a `Value<'static>` can
175//! be passed wherever a shorter `Value<'a>` is expected. To store a
176//! decoded or constructed `Value` in a struct field where a lifetime
177//! parameter would be inconvenient, name it `Value<'static>`:
178//!
179//! ```
180//! use cbor_core::Value;
181//!
182//! struct Config {
183//! metadata: Value<'static>,
184//! }
185//!
186//! impl Config {
187//! fn new() -> Self {
188//! // `Value::read_from` and owned-input conversions like
189//! // `Value::from(42)` or `Value::from(String::from("..."))`
190//! // both yield values that can be stored as `Value<'static>`.
191//! Self { metadata: Value::from(42) }
192//! }
193//! }
194//! ```
195//!
196//! When a borrowed value needs to outlive its source slice, detach
197//! it explicitly. Three methods produce a `Value` that borrows
198//! nothing from the original input:
199//!
200//! * [`Value::into_owned`] consumes a [`Value`] and copies any
201//! borrowed strings into owned allocations. Cheapest when you
202//! can give up ownership of the original.
203//! * [`Value::to_owned`] does the same from `&Value`, leaving the
204//! original intact at the cost of cloning all owned data too.
205//! * [`Value::decode_owned`] decodes directly into an owned
206//! [`Value`], skipping the borrowed intermediate. Useful when
207//! the input buffer is local to the decode call.
208//!
209//! All three produce a `Value` that can be assigned to any lifetime,
210//! including `Value<'static>`.
211//!
212//! # Encoding rules
213//!
214//! Encoding is deterministic: integers and floats use their shortest
215//! form, and map keys are sorted in canonical order. The decoder
216//! rejects input that deviates. Pair [`DecodeOptions`] with
217//! [`Strictness`] to accept and normalize input that does not follow
218//! these rules.
219//!
220//! NaN payloads, including signaling NaNs, survive round-trips
221//! bit-for-bit. Float-width conversions go through bit patterns to
222//! avoid hardware canonicalization.
223//!
224//! # Sequences
225//!
226//! A CBOR sequence is zero or more items concatenated
227//! without framing. The read side is configured with [`Format`]; the
228//! encode side uses [`EncodeFormat`], which adds output-only variants
229//! ([`DiagnosticPretty`](EncodeFormat::DiagnosticPretty)) and accepts
230//! any [`Format`] through `impl Into<EncodeFormat>`.
231//!
232//! On the read side, [`DecodeOptions::sequence_decoder`] wraps a byte
233//! slice and yields a [`SequenceDecoder`] with
234//! `Item = Result<Value, Error>`.
235//! [`DecodeOptions::sequence_reader`] wraps any `io::Read` and yields
236//! a [`SequenceReader`] with `Item = Result<Value, IoError>`.
237//!
238//! In binary and hex, items sit back-to-back. In diagnostic notation,
239//! items are comma-separated, with an optional trailing comma.
240//!
241//! On the encode side, [`SequenceWriter::new`] takes an `io::Write`
242//! and an `impl Into<EncodeFormat>`, so a [`Format`] or an
243//! [`EncodeFormat`] can be passed directly. Items are fed in through:
244//!
245//! * [`write_item`](SequenceWriter::write_item) for a single `&Value`.
246//! * [`write_items`](SequenceWriter::write_items) for any
247//! `IntoIterator<Item = &Value>`.
248//! * [`write_pairs`](SequenceWriter::write_pairs) for an
249//! `IntoIterator<Item = (&Value, &Value)>`, which emits each key
250//! and value as two consecutive items. This matches the shape of
251//! `&BTreeMap::iter()`, so a map held in a `Value` streams straight
252//! into a sequence.
253//!
254//! [`Array`] and [`Map`] bridge between a sequence and an owned
255//! collection:
256//!
257//! * [`Array::from_sequence`] collects an `IntoIterator<Item = Value>`
258//! into an array.
259//! * [`Array::try_from_sequence`] takes a fallible iterator
260//! (`Item = Result<Value, E>`) and short-circuits on the first
261//! error.
262//! * [`Map::from_pairs`] consumes `(Value, Value)` pairs with
263//! last-write-wins on duplicate keys.
264//! * [`Map::try_from_pairs`] rejects duplicates with
265//! [`Error::NonDeterministic`].
266//! * [`Map::from_sequence`] takes an `IntoIterator<Item = Value>` of
267//! alternating key and value items in strict canonical order.
268//! * [`Map::try_from_sequence`] is the fallible-input form of
269//! [`from_sequence`](Map::from_sequence).
270//!
271//! The `try_*` forms take fallible iterators directly, so a
272//! [`SequenceDecoder`] or [`SequenceReader`] can feed an [`Array`] or
273//! [`Map`] without an intermediate `Vec`.
274//! [`Map::try_from_sequence`] uses the bound `E: From<Error>`, which
275//! covers both iterators because [`IoError`] already has
276//! `From<Error>`.
277//!
278//! ```
279//! use cbor_core::{Array, DecodeOptions, Format, SequenceWriter, Value};
280//!
281//! let items = [Value::from(1), Value::from("hi"), Value::from(true)];
282//!
283//! let mut buf = Vec::new();
284//! SequenceWriter::new(&mut buf, Format::Binary)
285//! .write_items(items.iter())
286//! .unwrap();
287//!
288//! let array = Array::try_from_sequence(
289//! DecodeOptions::new().sequence_decoder(&buf),
290//! ).unwrap();
291//! assert_eq!(array.get_ref().as_slice(), &items);
292//! ```
293//!
294//! # Optional features
295//!
296//! | Feature name | Enables |
297//! |---|---|
298//! | `serde` | `Serialize`/`Deserialize` for `Value`, [`Value::serialized`], [`Value::deserialized`] |
299//! | `chrono` | Conversions between `chrono::DateTime` and `DateTime`/`EpochTime`/`Value` |
300//! | `time` | Conversions between `time::UtcDateTime`/`time::OffsetDateTime` and `DateTime`/`EpochTime`/`Value` |
301//! | `jiff` | Conversions between `jiff::Timestamp`/`jiff::Zoned` and `DateTime`/`EpochTime`/`Value` |
302//! | `half` | `From`/`TryFrom` conversions between `Float`/`Value` and `half::f16` |
303//! | `num-bigint` | `From`/`TryFrom` conversions between `Value` and `num_bigint::BigInt`/`BigUint` |
304//! | `crypto-bigint` | `From`/`TryFrom` conversions between `Value` and `crypto_bigint::Uint`/`Int`/`NonZero` |
305//! | `rug` | `From`/`TryFrom` conversions between `Value` and `rug::Integer` |
306
307mod array;
308mod bytes;
309mod codec;
310mod data_type;
311mod date_time;
312mod decode_options;
313mod decoder;
314mod encoder;
315mod epoch_time;
316mod error;
317mod ext;
318mod float;
319mod format;
320mod integer;
321mod io;
322mod iso3339;
323mod limits;
324mod macros;
325mod map;
326mod parse;
327mod simple_value;
328mod strictness;
329mod tag;
330mod text;
331mod util;
332mod value;
333mod value_key;
334mod view;
335
336pub use array::Array;
337pub use bytes::ByteString;
338pub use data_type::DataType;
339pub use date_time::DateTime;
340pub use decode_options::DecodeOptions;
341pub use decoder::{SequenceDecoder, SequenceReader};
342pub use encoder::SequenceWriter;
343pub use epoch_time::EpochTime;
344pub use error::{Error, IoError, IoResult, Result};
345pub use float::Float;
346pub use format::{EncodeFormat, Format};
347pub use map::Map;
348pub use simple_value::SimpleValue;
349pub use strictness::Strictness;
350pub use text::TextString;
351pub use value::Value;
352pub use value_key::ValueKey;
353
354#[cfg(feature = "serde")]
355pub use ext::serde;
356#[cfg(feature = "serde")]
357#[doc(no_inline)]
358pub use serde::SerdeError;
359
360use integer::*;
361
362#[cfg(test)]
363mod tests;