Skip to main content

Crate deser_cbor

Crate deser_cbor 

Source
Expand description

Parse and serialize CBOR compatible with deser.

let bytes = deser_cbor::to_vec(&vec![1u64, 2, 3, 4]).unwrap();
assert_eq!(bytes, [0x84, 0x01, 0x02, 0x03, 0x04]);
let vec: Vec<u64> = deser_cbor::from_slice(&bytes).unwrap();
assert_eq!(vec, [1, 2, 3, 4]);

§Data Model

The deser data model maps onto CBOR as follows:

deserCBOR
Nullnull (undefined is also read as Null)
Boolfalse / true
U64, I64unsigned and negative integers
u128, i128integers or bignums (tags 2 and 3)
BigIntbignums (tags 2 and 3)
Datetimedate/time (tag 0), full-date (tag 1004) or text
Timestampepoch date/time (tag 1) or date/time (tag 0)
UuidUUIDs (tag 37)
Decimaldecimal fractions (tag 4)
F32, F64half, single or double precision floats
Str, Chartext strings
Bytesbyte strings
maps and sequencesmaps and arrays
Simpleunassigned simple values

Offset date-times are written with tag 0, local dates with tag 1004 and other date-times as plain text strings. Timestamps are written with tag 1 unless they have a fraction of a second, then they are written as date/time string (tag 0) which retains the precision. Other extension values (such as Duration) are written as their fallback.

Serialization produces the preferred serialization of RFC 8949: the shortest form is used for integers and lengths, floats are written in the shortest form that preserves their value and all maps and arrays have a definite length. With SerializerConfig::set_canonical map entries are additionally sorted to produce a deterministic encoding.

Deserialization accepts all well-formed CBOR including indefinite length strings, arrays and maps. Map keys can be of any type. Integers that do not fit into 64 bits are passed on as u128 / i128 extension atoms and larger ones as BigInt. The tags 0, 4, 37 and 1004 are turned into the well-known types Datetime, Decimal and Uuid if their content is valid. Epoch based date/times (tag 1) are passed on as tagged numbers, Timestamp accepts them. All floats are read as F64: RFC 8949 does not distinguish the precisions in the data model, the shortest one that preserves the value is picked when writing.

§Raw Values

RawCbor holds the CBOR encoding of a value. The encoding of values that are deserialized from CBOR is kept as it is (including tags and how lengths and integers were encoded): it’s validated but not deserialized, and written out again unchanged unless canonical output is requested. Values of other formats are encoded as CBOR.

use deser_cbor::RawCbor;

#[derive(deser::Deserialize, deser::Serialize)]
struct Record {
    id: u32,
    payload: RawCbor<'static>,
}

// {"id": 1, "payload": [_ 1, 2]}
let input = [
    0xa2, 0x62, b'i', b'd', 0x01, 0x67, b'p', b'a', b'y', b'l', b'o',
    b'a', b'd', 0x9f, 0x01, 0x02, 0xff,
];
let record: Record = deser_cbor::from_slice(&input).unwrap();
assert_eq!(record.payload.as_bytes(), [0x9f, 0x01, 0x02, 0xff]);
assert_eq!(record.payload.deserialize::<Vec<u32>>().unwrap(), [1, 2]);
assert_eq!(deser_cbor::to_vec(&record).unwrap(), input);

See Raw for more information.

§Features

  • io (enabled by default): reading and writing streams of the standard library, see streams. Requires std.
  • speedups (enabled by default): validates UTF-8 with simdutf8.
  • std (enabled by default): uses the standard library. Without it this crate only needs alloc (see no_std).

§Streams

Data items are read from a Read with from_reader and written to a Write with to_writer. To read or write CBOR sequences (data items that follow each other, for instance on a socket) the configurations create readers and writers of deser::io (DeserializerConfig::reader and SerializerConfig::writer). The reader only buffers until an item is complete:

use deser_cbor::{DeserializerConfig, SerializerConfig};

let mut writer = SerializerConfig::new().writer(Vec::new());
writer.write(&vec![1u32, 2]).unwrap();
writer.write(&"three").unwrap();
let bytes = writer.into_inner();

let mut reader = DeserializerConfig::new().reader(&bytes[..]);
assert_eq!(reader.read::<Vec<u32>>().unwrap(), Some(vec![1, 2]));
assert_eq!(reader.read::<String>().unwrap().as_deref(), Some("three"));
assert_eq!(reader.read::<String>().unwrap(), None);

The stream serializer (Serializer) and the stream deserializer (StreamDeserializer) do not do IO themselves (see deser::stream), they also work with other kinds of IO (for instance async runtimes with deser-tokio) and without the standard library.

§Tags

Tags are not part of the deser data model. Instead they are exchanged out of band through the State:

  • When deserializing, the tags in front of a data item are published into the state for the first event of the item (the atom or the start of the map or sequence). Types can pick them up with take_tag. Types which do not care about tags never see them, which means that unknown tags are transparent.
  • When serializing, push_tag registers a tag of a value in the state and the serializer writes it in front of the data item.
  • Tagged captures the outermost tag of a value and writes it.

Both directions use the same event data. This means that values which capture event data (such as Recording) keep the tags: CBOR that is deserialized into a recording and serialized again retains its tags.

The simplest way to work with tags is the Tagged wrapper.

The bignum tags 2 and 3 are handled by the format itself: they are converted to and from integers (and BigInt for bignums that do not fit into 128 bits). The same applies to the tags of the well-known types: date/time strings (tag 0), decimal fractions (tag 4), UUIDs (tag 37) and full-date strings (tag 1004) are converted to and from the respective well-known types if their content is valid. Otherwise they are passed on as tagged values.

Structs§

Cbor
The CBOR format of RawCbor values.
Deserializer
Deserializes a deserializable from CBOR.
DeserializerConfig
Configures how CBOR is deserialized.
DeserializerConfigBuilder
Builds a DeserializerConfig.
Iter
An iterator over the data items of a CBOR sequence.
Serializer
Serializes values into CBOR.
SerializerConfig
Configures how values are serialized to CBOR.
SerializerConfigBuilder
Builds a SerializerConfig.
Simple
A CBOR simple value.
StreamDeserializer
Reads a stream of CBOR data items into items (see deser::stream).
Tagged
A value with an optional CBOR tag.

Functions§

from_reader
Deserializes a data item from a reader.
from_slice
Deserializes a value from CBOR.
push_tag
Registers a tag to be written in front of the next data item.
take_tag
Takes the outermost tag of the current data item from the state.
to_vec
Serializes a value to CBOR.
to_writer
Serializes a value to a writer.

Type Aliases§

RawCbor
The CBOR encoding of a value.