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`).
9//!
10//! The central type is an owned [`Value`]. It can be constructed,
11//! inspected, modified in place, encoded to bytes, and decoded back.
12//! The API follows CBOR's own shape, so tagged values, simple values,
13//! and arbitrary map keys stay directly reachable without a detour
14//! through a schema.
15//!
16//! # Types
17//!
18//! [`Value`] is the owned representation of any CBOR data item. It handles
19//! construction, inspection, encoding, and decoding, and is what most code
20//! works with directly.
21//!
22//! * [`Array`], [`Map`], [`Float`], [`DateTime`], [`EpochTime`], and
23//! [`SimpleValue`] appear in `From`/`Into` bounds for `Value` and are
24//! rarely constructed by hand.
25//! * [`DataType`] reports a value's kind for type-based dispatch.
26//! [`ValueKey`] is the key type for maps.
27//! * [`DecodeOptions`] configures the decoder and [`Format`] selects
28//! binary, hex, or diagnostic input. [`SequenceDecoder`] and
29//! [`SequenceReader`] iterate over CBOR sequences; [`SequenceWriter`]
30//! is their encode-side counterpart, configured with [`EncodeFormat`].
31//! * [`Error`] and [`Result`] cover in-memory decoding; [`IoError`] and
32//! [`IoResult`] cover `io::Read` sources.
33//!
34//! # Quick start
35//!
36//! ```
37//! use cbor_core::{Value, array, map};
38//!
39//! // Build a value
40//! let value = map! {
41//! 1 => "hello",
42//! 2 => array![10, 20, 30],
43//! };
44//!
45//! // Encode to bytes and decode back
46//! let bytes = value.encode();
47//! let decoded = Value::decode(&bytes).unwrap();
48//! assert_eq!(value, decoded);
49//!
50//! // Access inner data
51//! let greeting = decoded[1].as_str().unwrap();
52//! assert_eq!(greeting, "hello");
53//!
54//! // Round-trip through diagnostic notation
55//! let text = format!("{value:?}");
56//! let parsed: Value = text.parse().unwrap();
57//! assert_eq!(value, parsed);
58//! ```
59//!
60//! # Diagnostic notation
61//!
62//! [`Value`] implements [`FromStr`](std::str::FromStr), so any CBOR value can
63//! be written as text and parsed with `str::parse`. This is often the
64//! shortest way to build a literal value in a test, a fixture, or an
65//! example, and it avoids manual `Value::from` chains for nested data.
66//!
67//! The grammar is Section 2.3.6 of the CBOR::Core draft. Examples:
68//!
69//! ```
70//! use cbor_core::Value;
71//!
72//! // Integers in any base, with `_` as a digit separator
73//! let v: Value = "0xff_ff_00_00".parse().unwrap();
74//! assert_eq!(v, Value::from(0xff_ff_00_00_u32));
75//!
76//! // Arbitrary precision: parsed as tag 2 / tag 3 big integers
77//! let big: Value = "18446744073709551616".parse().unwrap();
78//! assert_eq!(big, Value::from(u64::MAX as u128 + 1));
79//!
80//! // Floats, including explicit bit patterns for NaN payloads
81//! let f: Value = "1.5e2".parse().unwrap();
82//! assert_eq!(f, Value::from(150.0));
83//! let nan: Value = "float'7f800001'".parse().unwrap();
84//! assert_eq!(nan.encode(), vec![0xfa, 0x7f, 0x80, 0x00, 0x01]);
85//!
86//! // Byte strings: hex, base64, ASCII, or embedded CBOR
87//! assert_eq!("h'48656c6c6f'".parse::<Value>().unwrap(), Value::from(b"Hello".to_vec()));
88//! assert_eq!("b64'SGVsbG8'".parse::<Value>().unwrap(), Value::from(b"Hello".to_vec()));
89//! assert_eq!("'Hello'".parse::<Value>().unwrap(), Value::from(b"Hello".to_vec()));
90//! // << ... >> wraps a CBOR sequence into a byte string
91//! assert_eq!(
92//! "<< 1, 2, 3 >>".parse::<Value>().unwrap(),
93//! Value::from(vec![0x01, 0x02, 0x03]),
94//! );
95//! ```
96//!
97//! Nested structures are written directly, and maps may appear in any
98//! order. The parser sorts keys and rejects duplicates:
99//!
100//! ```
101//! use cbor_core::Value;
102//!
103//! let cert: Value = r#"{
104//! / CWT-style claims, written out of canonical order /
105//! "iss": "https://issuer.example",
106//! "sub": "user-42",
107//! "iat": 1700000000,
108//! "cnf": {
109//! "kty": "OKP",
110//! "crv": "Ed25519",
111//! "x": h'd75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a'
112//! },
113//! "scope": ["read", "write"]
114//! }"#.parse().unwrap();
115//!
116//! assert_eq!(cert["sub"].as_str().unwrap(), "user-42");
117//! assert_eq!(cert["cnf"]["crv"].as_str().unwrap(), "Ed25519");
118//! ```
119//!
120//! Supported grammar elements: integers (decimal, `0x`, `0o`, `0b`, with
121//! `_` separators), arbitrary-precision integers, floats (decimal,
122//! scientific, `NaN`, `Infinity`, `float'<hex>'`), text strings with
123//! JSON-style escapes and surrogate pairs, byte strings (`h'...'`,
124//! `b64'...'`, `'...'`, `<<...>>`), arrays, maps, tagged values `N(...)`,
125//! `simple(N)`, `true`, `false`, `null`, single-line `# ...` comments, and
126//! block `/ ... /` comments.
127//!
128//! The parser accepts non-canonical input (for example unsorted maps and
129//! non-shortest numbers), normalizes it, and produces a canonical [`Value`].
130//! Round-tripping `format!("{v:?}").parse::<Value>()` always yields the
131//! original value.
132//!
133//! # Encoding rules
134//!
135//! Encoding is deterministic: integers and floats use their shortest
136//! form, and map keys are sorted in canonical order. The decoder
137//! rejects input that deviates.
138//!
139//! NaN payloads, including signaling NaNs, survive round-trips
140//! bit-for-bit. Float-width conversions go through bit patterns to
141//! avoid hardware canonicalization.
142//!
143//! # Sequences
144//!
145//! A CBOR sequence is zero or more items concatenated
146//! without framing. The read side is configured with [`Format`]; the
147//! encode side uses [`EncodeFormat`], which adds output-only variants
148//! ([`DiagnosticPretty`](EncodeFormat::DiagnosticPretty)) and accepts
149//! any [`Format`] through `impl Into<EncodeFormat>`.
150//!
151//! On the read side, [`DecodeOptions::sequence_decoder`] wraps a byte
152//! slice and yields a [`SequenceDecoder`] with
153//! `Item = Result<Value, Error>`.
154//! [`DecodeOptions::sequence_reader`] wraps any `io::Read` and yields
155//! a [`SequenceReader`] with `Item = Result<Value, IoError>`.
156//!
157//! In binary and hex, items sit back-to-back. In diagnostic notation,
158//! items are comma-separated, with an optional trailing comma.
159//!
160//! On the encode side, [`SequenceWriter::new`] takes an `io::Write`
161//! and an `impl Into<EncodeFormat>`, so a [`Format`] or an
162//! [`EncodeFormat`] can be passed directly. Items are fed in through:
163//!
164//! * [`write_item`](SequenceWriter::write_item) for a single `&Value`.
165//! * [`write_items`](SequenceWriter::write_items) for any
166//! `IntoIterator<Item = &Value>`.
167//! * [`write_pairs`](SequenceWriter::write_pairs) for an
168//! `IntoIterator<Item = (&Value, &Value)>`, which emits each key
169//! and value as two consecutive items. This matches the shape of
170//! `&BTreeMap::iter()`, so a map held in a `Value` streams straight
171//! into a sequence.
172//!
173//! [`Array`] and [`Map`] bridge between a sequence and an owned
174//! collection:
175//!
176//! * [`Array::from_sequence`] collects an `IntoIterator<Item = Value>`
177//! into an array.
178//! * [`Array::try_from_sequence`] takes a fallible iterator
179//! (`Item = Result<Value, E>`) and short-circuits on the first
180//! error.
181//! * [`Map::from_pairs`] consumes `(Value, Value)` pairs with
182//! last-write-wins on duplicate keys.
183//! * [`Map::try_from_pairs`] rejects duplicates with
184//! [`Error::NonDeterministic`].
185//! * [`Map::from_sequence`] takes an `IntoIterator<Item = Value>` of
186//! alternating key and value items in strict canonical order.
187//! * [`Map::try_from_sequence`] is the fallible-input form of
188//! [`from_sequence`](Map::from_sequence).
189//!
190//! The `try_*` forms take fallible iterators directly, so a
191//! [`SequenceDecoder`] or [`SequenceReader`] can feed an [`Array`] or
192//! [`Map`] without an intermediate `Vec`.
193//! [`Map::try_from_sequence`] uses the bound `E: From<Error>`, which
194//! covers both iterators because [`IoError`] already has
195//! `From<Error>`.
196//!
197//! ```
198//! use cbor_core::{Array, DecodeOptions, Format, SequenceWriter, Value};
199//!
200//! let items = [Value::from(1), Value::from("hi"), Value::from(true)];
201//!
202//! let mut buf = Vec::new();
203//! SequenceWriter::new(&mut buf, Format::Binary)
204//! .write_items(items.iter())
205//! .unwrap();
206//!
207//! let array = Array::try_from_sequence(
208//! DecodeOptions::new().sequence_decoder(&buf),
209//! ).unwrap();
210//! assert_eq!(array.get_ref().as_slice(), &items);
211//! ```
212//!
213//! # Optional features
214//!
215//! | Feature | Adds |
216//! |---|---|
217//! | `serde` | `Serialize`/`Deserialize` for `Value`, [`serde::to_value`], [`serde::from_value`] |
218//! | `chrono` | Conversions between `chrono::DateTime` and `DateTime`/`EpochTime`/`Value` |
219//! | `time` | Conversions between `time::UtcDateTime`/`OffsetDateTime` and `DateTime`/`EpochTime`/`Value` |
220//! | `jiff` | Conversions between `jiff::Timestamp`/`Zoned` and `DateTime`/`EpochTime`/`Value` |
221//! | `half` | `From`/`TryFrom` between `Float`/`Value` and `half::f16` |
222//! | `num-bigint` | `From`/`TryFrom` between `Value` and `num_bigint::BigInt`/`BigUint` |
223//! | `crypto-bigint` | `From`/`TryFrom` between `Value` and `crypto_bigint::Uint`/`Int`/`NonZero` |
224//! | `rug` | `From`/`TryFrom` between `Value` and `rug::Integer` |
225
226mod array;
227mod codec;
228mod data_type;
229mod date_time;
230mod decode_options;
231mod decoder;
232mod encoder;
233mod epoch_time;
234mod error;
235mod ext;
236mod float;
237mod format;
238mod integer;
239mod io;
240mod iso3339;
241mod limits;
242mod macros;
243mod map;
244mod parse;
245mod simple_value;
246mod tag;
247mod util;
248mod value;
249mod value_key;
250mod view;
251
252pub use array::Array;
253pub use data_type::DataType;
254pub use date_time::DateTime;
255pub use decode_options::DecodeOptions;
256pub use decoder::{SequenceDecoder, SequenceReader};
257pub use encoder::SequenceWriter;
258pub use epoch_time::EpochTime;
259pub use error::{Error, IoError, IoResult, Result};
260pub use float::Float;
261pub use format::{EncodeFormat, Format};
262pub use map::Map;
263pub use simple_value::SimpleValue;
264pub use value::Value;
265pub use value_key::ValueKey;
266
267#[cfg(feature = "serde")]
268pub use ext::serde;
269
270use integer::*;
271
272#[cfg(test)]
273mod tests;