cbor_core/lib.rs
1#![forbid(unsafe_code)]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3
4//! Deterministic CBOR encoder and decoder following the
5//! [CBOR::Core](https://www.ietf.org/archive/id/draft-rundgren-cbor-core-25.html)
6//! profile (`draft-rundgren-cbor-core-25`).
7//!
8//! This crate works with CBOR as an owned data structure rather than as a
9//! serialization layer. Values can be constructed, inspected, modified, and
10//! round-tripped through their canonical byte encoding.
11//!
12//! # Types
13//!
14//! [`Value`] is the central type and a good starting point. It holds any
15//! CBOR data item and provides constructors, accessors, encoding, and
16//! decoding.
17//!
18//! | Type | Role |
19//! |------|------|
20//! | [`Value`] | Any CBOR data item. Start here. |
21//! | [`SimpleValue`] | CBOR simple value (`null`, `true`, `false`, 0-255). |
22//! | [`DataType`] | Classification of a value for type-level dispatch. |
23//! | [`Error`] | All errors produced by this crate. |
24//!
25//! The following types are helpers that appear in `From`/`Into` bounds
26//! and are rarely used directly:
27//!
28//! | Type | Role |
29//! |------|------|
30//! | [`Array`] | Wrapper around `Vec<Value>` accepted by array constructors. |
31//! | [`Map`] | Wrapper around `BTreeMap<Value, Value>` accepted by map constructors. |
32//! | [`Float`] | IEEE 754 float stored in shortest CBOR form (f16, f32, or f64). |
33//! | [`DateTime`] | Validated ISO 8601 UTC string for tag 0 construction. |
34//! | [`EpochTime`] | Validated numeric epoch time for tag 1 construction. |
35//!
36//! # Quick start
37//!
38//! ```
39//! use cbor_core::{Value, array, map};
40//!
41//! // Build a value
42//! let value = map! {
43//! 1 => "hello",
44//! 2 => array![10, 20, 30],
45//! };
46//!
47//! // Encode to bytes and decode back
48//! let bytes = value.encode();
49//! let decoded = Value::decode(&bytes).unwrap();
50//! assert_eq!(value, decoded);
51//!
52//! // Access inner data
53//! let greeting = decoded[1].as_str().unwrap();
54//! assert_eq!(greeting, "hello");
55//!
56//! // Round-trip through diagnostic notation
57//! let text = format!("{value:?}");
58//! let parsed: Value = text.parse().unwrap();
59//! assert_eq!(value, parsed);
60//! ```
61//!
62//! # Diagnostic notation
63//!
64//! `Value` implements [`FromStr`](std::str::FromStr), so any CBOR value can
65//! be written as text and parsed with `str::parse`. This is often the
66//! shortest way to build a literal value in a test, a fixture, or an
67//! example, and it avoids manual `Value::from` chains for nested data.
68//!
69//! The grammar is Section 2.3.6 of the CBOR::Core draft. Examples:
70//!
71//! ```
72//! use cbor_core::Value;
73//!
74//! // Integers in any base, with `_` as a digit separator
75//! let v: Value = "0xff_ff_00_00".parse().unwrap();
76//! assert_eq!(v, Value::from(0xff_ff_00_00_u32));
77//!
78//! // Arbitrary precision: parsed as tag 2 / tag 3 big integers
79//! let big: Value = "18446744073709551616".parse().unwrap();
80//! assert_eq!(big, Value::from(u64::MAX as u128 + 1));
81//!
82//! // Floats, including explicit bit patterns for NaN payloads
83//! let f: Value = "1.5e2".parse().unwrap();
84//! assert_eq!(f, Value::from(150.0));
85//! let nan: Value = "float'7f800001'".parse().unwrap();
86//! assert_eq!(nan.encode(), vec![0xfa, 0x7f, 0x80, 0x00, 0x01]);
87//!
88//! // Byte strings: hex, base64, ASCII, or embedded CBOR
89//! assert_eq!("h'48656c6c6f'".parse::<Value>().unwrap(), Value::from(b"Hello".to_vec()));
90//! assert_eq!("b64'SGVsbG8'".parse::<Value>().unwrap(), Value::from(b"Hello".to_vec()));
91//! assert_eq!("'Hello'".parse::<Value>().unwrap(), Value::from(b"Hello".to_vec()));
92//! // << ... >> wraps a CBOR sequence into a byte string
93//! assert_eq!(
94//! "<< 1, 2, 3 >>".parse::<Value>().unwrap(),
95//! Value::ByteString(vec![0x01, 0x02, 0x03]),
96//! );
97//! ```
98//!
99//! Nested structures are written directly, and maps may appear in any
100//! order. The parser sorts keys and rejects duplicates:
101//!
102//! ```
103//! use cbor_core::Value;
104//!
105//! let cert: Value = r#"{
106//! / CWT-style claims, written out of canonical order /
107//! "iss": "https://issuer.example",
108//! "sub": "user-42",
109//! "iat": 1700000000,
110//! "cnf": {
111//! "kty": "OKP",
112//! "crv": "Ed25519",
113//! "x": h'd75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a'
114//! },
115//! "scope": ["read", "write"]
116//! }"#.parse().unwrap();
117//!
118//! assert_eq!(cert["sub"].as_str().unwrap(), "user-42");
119//! assert_eq!(cert["cnf"]["crv"].as_str().unwrap(), "Ed25519");
120//! ```
121//!
122//! Supported grammar elements: integers (decimal, `0x`, `0o`, `0b`, with
123//! `_` separators), arbitrary-precision integers, floats (decimal,
124//! scientific, `NaN`, `Infinity`, `float'<hex>'`), text strings with
125//! JSON-style escapes and surrogate pairs, byte strings (`h'...'`,
126//! `b64'...'`, `'...'`, `<<...>>`), arrays, maps, tagged values `N(...)`,
127//! `simple(N)`, `true`, `false`, `null`, single-line `# ...` comments, and
128//! block `/ ... /` comments.
129//!
130//! The parser accepts non-canonical input (for example unsorted maps and
131//! non-shortest numbers), normalizes it, and produces a canonical `Value`.
132//! Round-tripping `format!("{v:?}").parse::<Value>()` always yields the
133//! original value.
134//!
135//! # Encoding rules
136//!
137//! All encoding is deterministic: integers and floats use their shortest
138//! representation, and map keys are sorted in CBOR canonical order. The
139//! decoder rejects non-canonical input.
140//!
141//! NaN values, including signaling NaNs and custom payloads, are preserved
142//! through encode/decode round-trips. Conversion between float widths uses
143//! bit-level manipulation to avoid hardware NaN canonicalization.
144//!
145//! # Optional features
146//!
147//! | Feature | Adds |
148//! |---|---|
149//! | `serde` | `Serialize`/`Deserialize` for `Value`, [`serde::to_value`], [`serde::from_value`] |
150//! | `chrono` | Conversions between `chrono::DateTime` and `DateTime`/`EpochTime`/`Value` |
151//! | `time` | Conversions between `time::UtcDateTime`/`OffsetDateTime` and `DateTime`/`EpochTime`/`Value` |
152//! | `half` | `From`/`TryFrom` between `Float`/`Value` and `half::f16` |
153//! | `num-bigint` | `From`/`TryFrom` between `Value` and `num_bigint::BigInt`/`BigUint` |
154//! | `crypto-bigint` | `From`/`TryFrom` between `Value` and `crypto_bigint::Uint`/`Int`/`NonZero` |
155//! | `rug` | `From`/`TryFrom` between `Value` and `rug::Integer` |
156
157mod array;
158mod codec;
159mod data_type;
160mod date_time;
161mod epoch_time;
162mod error;
163mod ext;
164mod float;
165mod integer;
166mod io;
167mod iso3339;
168mod limits;
169mod macros;
170mod map;
171mod parse;
172mod simple_value;
173mod tag;
174mod util;
175mod value;
176mod value_key;
177
178pub use array::Array;
179pub use data_type::DataType;
180pub use date_time::DateTime;
181pub use epoch_time::EpochTime;
182pub use error::{Error, IoError, IoResult, Result};
183pub use float::Float;
184pub use map::Map;
185pub use simple_value::SimpleValue;
186pub use value::Value;
187pub use value_key::ValueKey;
188
189#[cfg(feature = "serde")]
190#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
191pub use ext::serde;
192
193use integer::*;
194
195#[cfg(test)]
196mod tests;