zerocbor
A zero-copy, zero-dependency, no_std-compatible, extremely fast CBOR (RFC 8949) serializer for Rust.
Overview
zerocbor is a fast CBOR serializer for Rust. It runs about 1.5–4.0 times faster than other crates and is implemented without depending on any libraries, including std.
zerocbor is based on the architecture of zerompk, with the serialization format switched to CBOR. zerompk is a fast MessagePack serializer characterized by high performance and a small code size compared with conventional serializers. See the zerompk README for details.
Quick Start
use ;
Format
The mapping between Rust types and CBOR types in zerocbor is as follows.
| Rust Type | CBOR Major Type |
|---|---|
bool |
7, simple value true / false |
u8, u16, u32, u64, usize |
0, unsigned integer |
i8, i16, i32, i64, isize |
0 or 1, unsigned or negative integer |
f32 |
7, float 16 or float 32, whichever is narrower |
f64 |
7, whichever of the three float widths is narrowest |
char |
3, one-character text string |
str, String |
3, text string |
&'a [u8] (decode) |
2, byte string |
&[u8], Vec<u8> (encode) |
4, array of integers — see the note below |
&[T], Vec<T>, VecDeque<T>, LinkedList<T>, BTreeSet<T>, BinaryHeap<T>, HashSet<T> |
4, array |
BTreeMap<K, V>, HashMap<K, V> |
5, map |
() |
7, simple value null |
Option<T> |
7, null (None) or T (Some(T)) |
Result<T, E> |
4, [true, T] (Ok) or [false, E] (Err) |
newtype struct W(T) |
as T, optionally under a tag |
(T0, T1), (T0, T1, T2), ... |
4, array |
Box<T>, Rc<T>, Arc<T> |
as T |
PhantomData<T> |
7, simple value null |
| struct (default, array representation) | 4, array of the fields in declaration order |
struct (with #[cbor(map)]) |
5, map keyed by field name |
| enum, fieldless variants (default) | 0, the variant index |
enum, fieldless variants (with #[cbor(map)]) |
3, the variant name |
| enum with data (default) | 4, [index, fields...] |
enum with data (with #[cbor(map)]) |
5, {"Name": value} where value is the fields |
anything with #[cbor(tag = N)] |
6, the tag, then the value it applies to |
derive
Enable the derive feature flag to implement FromCbor/ToCbor using derive macros.
use ;
You can also customize the serialization format using the #[cbor] attribute.
array/map
You can choose array or map as the serialization format for structs and enums. For performance reasons, the default is array.
use ;
// default
key
You can override the index/key used for fields and enum variants. Integers can be used for arrays, and strings for maps. When the format is array and there are gaps in the indices, null is inserted automatically.
[!NOTE] To improve versioning resilience, it is recommended to set keys explicitly whenever possible.
ignore
Set ignore on fields that should be ignored during serialization/deserialization. When deserializing a struct that contains an ignore field, the field's type must implement Default.
c_enum
Adding #[cbor(c_enum)] to a C-style enum allows it to be serialized as an integer. The value is the discriminant of each variant.
as_bytes
You can specify whether a u8 array is serialized as binary data (major type 2). The default is true. This option can be applied to fields of type &[u8], Vec<u8>, or Cow<[u8]>.
use Cow;
use ;
let value = Blob ;
let encoded = to_cbor_vec.unwrap;
assert_eq!;
assert_eq!;
default
If a key is missing during deserialization, the corresponding field is replaced with a default value. A missing key is filled with Default::default(), or, if default = "path" is specified, with the result of the named function.
This is supported only with #[cbor(map)]. (Because arrays have no field names, missing values cannot be detected safely.)
use ;
default applies only to missing keys. Unknown keys cause an error unless allow_unknown_fields is set.
allow_unknown_fields
When an unknown key is encountered during deserialization, this changes the behavior to skip it instead of returning an error. This is effective only with #[cbor(map)].
use ;
To ensure full forward and backward compatibility, combine default and allow_unknown_fields.
[!NOTE] These attributes are opt-in. By default, zerocbor requires an exact schema match.
Benchmarks
Measured on macOS 26.4.1 (arm64) with
rustc 1.100.0-nightly.
Serialize/Deserialize Struct (2 fields, array format)
| Crate | Serialize | Deserialize |
|---|---|---|
cbor4ii |
3.19 μs | 16.46 μs |
ciborium |
18.40 μs | 123.92 μs |
minicbor |
11.36 μs | 10.29 μs |
zerocbor |
1.54 μs | 5.03 μs |
Serialize/Deserialize Struct (4 fields, map format, with a nested struct, an Option and a Vec)
| Crate | Serialize | Deserialize |
|---|---|---|
cbor4ii |
34.52 μs | 180.49 μs |
ciborium |
90.69 μs | 491.88 μs |
minicbor |
64.42 μs | 150.32 μs |
zerocbor |
24.74 μs | 122.83 μs |
Serialize/Deserialize Struct (8 integer fields, one of every width)
| Crate | Serialize | Deserialize |
|---|---|---|
ciborium |
87.40 μs | 357.90 μs |
minicbor |
58.71 μs | 41.40 μs |
zerocbor |
8.54 μs | 27.15 μs |
Serialize/Deserialize Array (a 2-field struct plus a 1000-element Vec<u64>)
| Crate | Serialize | Deserialize |
|---|---|---|
cbor4ii |
2,289.96 μs | 6,544.41 μs |
ciborium |
6,175.27 μs | 15,511.02 μs |
minicbor |
11,050.64 μs | 5,625.04 μs |
zerocbor |
820.06 μs | 2,376.10 μs |
Serialize/Deserialize Struct (borrowed &str and byte string)
| Crate | Serialize | Deserialize |
|---|---|---|
cbor4ii |
11.74 μs | 27.33 μs |
ciborium |
23.84 μs | N/A |
minicbor |
N/A | N/A |
zerocbor |
8.71 μs | 17.80 μs |
Deserialize Array (1000 records) from a std::io::Read stream
| Crate | Deserialize |
|---|---|
cbor4ii |
124.05 μs |
ciborium |
96.32 μs |
zerocbor |
32.62 μs |
Decode/Encode a dynamically typed document into and out of Value
| Crate | Decode | Encode |
|---|---|---|
ciborium |
2.83 μs | 496.22 μs |
zerocbor |
1.32 μs | 365.69 μs |
License
This library is released under the MIT License.