Skip to main content

deser_cbor/
lib.rs

1//! Parse and serialize [CBOR](https://www.rfc-editor.org/rfc/rfc8949) compatible
2//! with deser.
3//!
4//! ```rust
5//! let bytes = deser_cbor::to_vec(&vec![1u64, 2, 3, 4]).unwrap();
6//! assert_eq!(bytes, [0x84, 0x01, 0x02, 0x03, 0x04]);
7//! let vec: Vec<u64> = deser_cbor::from_slice(&bytes).unwrap();
8//! assert_eq!(vec, [1, 2, 3, 4]);
9//! ```
10//!
11//! # Data Model
12//!
13//! The deser data model maps onto CBOR as follows:
14//!
15//! | deser                   | CBOR                                              |
16//! |-------------------------|---------------------------------------------------|
17//! | `Null`                  | `null` (`undefined` is also read as `Null`)       |
18//! | `Bool`                  | `false` / `true`                                  |
19//! | `U64`, `I64`            | unsigned and negative integers                    |
20//! | `u128`, `i128`          | integers or bignums (tags 2 and 3)                |
21//! | [`BigInt`]              | bignums (tags 2 and 3)                            |
22//! | [`Datetime`]            | date/time (tag 0), full-date (tag 1004) or text   |
23//! | [`Timestamp`]           | epoch date/time (tag 1) or date/time (tag 0)      |
24//! | [`Uuid`]                | UUIDs (tag 37)                                    |
25//! | [`Decimal`]             | decimal fractions (tag 4)                         |
26//! | `F32`, `F64`            | half, single or double precision floats           |
27//! | `Str`, `Char`           | text strings                                      |
28//! | `Bytes`                 | byte strings                                      |
29//! | maps and sequences      | maps and arrays                                   |
30//! | [`Simple`]              | unassigned simple values                          |
31//!
32//! Offset date-times are written with tag 0, local dates with tag 1004 and
33//! other date-times as plain text strings.  Timestamps are written with tag
34//! 1 unless they have a fraction of a second, then they are written as
35//! date/time string (tag 0) which retains the precision.  Other extension
36//! values (such as [`Duration`](deser_core::ext::Duration)) are written as their
37//! fallback.
38//!
39//! Serialization produces the preferred serialization of RFC 8949: the
40//! shortest form is used for integers and lengths, floats are written in the
41//! shortest form that preserves their value and all maps and arrays have a
42//! definite length.  With [`SerializerConfig::set_canonical`] map entries are
43//! additionally sorted to produce a deterministic encoding.
44//!
45//! Deserialization accepts all well-formed CBOR including indefinite length
46//! strings, arrays and maps.  Map keys can be of any type.  Integers that
47//! do not fit into 64 bits are passed on as `u128` / `i128` extension atoms
48//! and larger ones as [`BigInt`].  The tags 0, 4, 37 and 1004 are turned
49//! into the well-known types [`Datetime`], [`Decimal`] and [`Uuid`] if their
50//! content is valid.  Epoch based date/times (tag 1) are passed on as tagged
51//! numbers, [`Timestamp`] accepts them.  All floats are read as `F64`: RFC
52//! 8949 does not distinguish the precisions in the data model, the shortest
53//! one that preserves the value is picked when writing.
54//!
55//! [`BigInt`]: deser_core::ext::BigInt
56//! [`Datetime`]: deser_core::ext::Datetime
57//! [`Timestamp`]: deser_core::ext::Timestamp
58//! [`Uuid`]: deser_core::ext::Uuid
59//! [`Decimal`]: deser_core::ext::Decimal
60//!
61//! # Raw Values
62//!
63//! [`RawCbor`] holds the CBOR encoding of a value.  The encoding of values
64//! that are deserialized from CBOR is kept as it is (including tags and
65//! how lengths and integers were encoded): it's validated but not
66//! deserialized, and written out again unchanged unless canonical output is
67//! requested.  Values of other formats are encoded as CBOR.
68//!
69//! ```rust
70//! use deser_cbor::RawCbor;
71//!
72//! #[derive(deser::Deserialize, deser::Serialize)]
73//! struct Record {
74//!     id: u32,
75//!     payload: RawCbor<'static>,
76//! }
77//!
78//! // {"id": 1, "payload": [_ 1, 2]}
79//! let input = [
80//!     0xa2, 0x62, b'i', b'd', 0x01, 0x67, b'p', b'a', b'y', b'l', b'o',
81//!     b'a', b'd', 0x9f, 0x01, 0x02, 0xff,
82//! ];
83//! let record: Record = deser_cbor::from_slice(&input).unwrap();
84//! assert_eq!(record.payload.as_bytes(), [0x9f, 0x01, 0x02, 0xff]);
85//! assert_eq!(record.payload.deserialize::<Vec<u32>>().unwrap(), [1, 2]);
86//! assert_eq!(deser_cbor::to_vec(&record).unwrap(), input);
87//! ```
88//!
89//! See [`Raw`](deser_core::ext::Raw) for more information.
90//!
91//! # Features
92//!
93//! * `io` (enabled by default): reading and writing streams of the
94//!   standard library, see [streams](#streams).  Requires `std`.
95//! * `speedups` (enabled by default): validates UTF-8 with [`simdutf8`](https://docs.rs/simdutf8).
96//! * `std` (enabled by default): uses the standard library.  Without it
97//!   this crate only needs `alloc` (see [`no_std`](https://docs.rs/deser/latest/deser/#no_std)).
98//!
99//! # Streams
100//!
101//! Data items are read from a [`Read`](std::io::Read) with [`from_reader`]
102//! and written to a [`Write`](std::io::Write) with [`to_writer`].  To read
103//! or write [CBOR sequences](https://www.rfc-editor.org/rfc/rfc8742) (data
104//! items that follow each other, for instance on a socket) the
105//! configurations create readers and writers of
106//! [`deser::io`](deser_core::io) ([`DeserializerConfig::reader`] and
107//! [`SerializerConfig::writer`]).  The reader only buffers until an item
108//! is complete:
109//!
110//! ```rust
111//! # #[cfg(feature = "io")] {
112//! use deser_cbor::{DeserializerConfig, SerializerConfig};
113//!
114//! let mut writer = SerializerConfig::new().writer(Vec::new());
115//! writer.write(&vec![1u32, 2]).unwrap();
116//! writer.write(&"three").unwrap();
117//! let bytes = writer.into_inner();
118//!
119//! let mut reader = DeserializerConfig::new().reader(&bytes[..]);
120//! assert_eq!(reader.read::<Vec<u32>>().unwrap(), Some(vec![1, 2]));
121//! assert_eq!(reader.read::<String>().unwrap().as_deref(), Some("three"));
122//! assert_eq!(reader.read::<String>().unwrap(), None);
123//! # }
124//! ```
125//!
126//! The stream serializer ([`Serializer`]) and the stream deserializer
127//! ([`StreamDeserializer`]) do not do IO themselves (see
128//! [`deser::stream`](deser_core::stream)), they also work with other kinds
129//! of IO (for instance async runtimes with `deser-tokio`) and without the
130//! standard library.
131//!
132//! # Tags
133//!
134//! Tags are not part of the deser data model.  Instead they are exchanged
135//! out of band through the [`State`](deser_core::State):
136//!
137//! * When deserializing, the tags in front of a data item are published into
138//!   the state for the first event of the item (the atom or the start of the
139//!   map or sequence).  Types can pick them up with
140//!   [`take_tag`].  Types which do not care about tags never see them, which
141//!   means that unknown tags are transparent.
142//! * When serializing, [`push_tag`] registers a tag of a value in the state
143//!   and the serializer writes it in front of the data item.
144//! * [`Tagged`] captures the outermost tag of a value and writes it.
145//!
146//! Both directions use the same event data.  This means that values which
147//! capture event data (such as [`Recording`](deser_core::de::Recording)) keep
148//! the tags: CBOR that is deserialized into a recording and serialized again
149//! retains its tags.
150//!
151//! The simplest way to work with tags is the [`Tagged`] wrapper.
152//!
153//! The bignum tags 2 and 3 are handled by the format itself: they are
154//! converted to and from integers (and [`BigInt`](deser_core::ext::BigInt) for
155//! bignums that do not fit into 128 bits).  The same applies to the tags of
156//! the well-known types: date/time strings (tag 0), decimal fractions (tag
157//! 4), UUIDs (tag 37) and full-date strings (tag 1004) are converted to and
158//! from the respective [well-known types](deser_core::ext) if their content is
159//! valid.  Otherwise they are passed on as tagged values.
160#![doc(html_logo_url = "https://raw.githubusercontent.com/mitsuhiko/deser/main/artwork/logo.svg")]
161#![cfg_attr(not(any(feature = "std", test)), no_std)]
162
163extern crate alloc;
164
165mod copy;
166mod de;
167mod float;
168mod parser;
169mod raw;
170mod ser;
171mod simple;
172mod stream;
173mod tag;
174
175pub use self::de::{Deserializer, DeserializerConfig, DeserializerConfigBuilder, Iter, from_slice};
176pub use self::raw::{Cbor, RawCbor};
177#[cfg(feature = "io")]
178pub use self::ser::to_writer;
179pub use self::ser::{Serializer, SerializerConfig, SerializerConfigBuilder, to_vec};
180pub use self::simple::Simple;
181pub use self::stream::StreamDeserializer;
182#[cfg(feature = "io")]
183pub use self::stream::from_reader;
184pub use self::tag::{Tagged, push_tag, take_tag};