cbor

A Rust library that encodes and decodes CBOR binary data through Serde's Serialize and Deserialize traits, with optional no_std support.

Library
Cargo
v0.11.2
309stars
Apache License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
39/100Needs Attention
Development Activity0
Maintenance20
Community56
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
72/100Good
Architecture80
Code Quality78
Innovation55
Learning Curve75

serde_cbor implements the Concise Binary Object Representation (RFC 7049) as a Serde data format, letting any type that already derives Serialize/Deserialize be written to and read from CBOR with no extra boilerplate. It builds directly on Serde’s generic serialization framework, so the same derive macros used for JSON or other formats work unchanged here, while CBOR’s compact binary encoding keeps payload sizes small.

Beyond the standard typed path, the crate exposes an untyped Value enum for working with CBOR documents whose shape isn’t known ahead of time, a packed encoding mode that replaces struct field names and enum variants with small integers to shrink output further, and no_std/alloc builds for embedded targets. The project was archived by its maintainer in August 2021 after roughly six years of use across hundreds of downstream crates; it still works as-is for existing consumers, though the README points newcomers toward actively maintained alternatives such as ciborium or minicbor.

What You Get

  • Type-based to_vec/to_writer/from_slice/from_reader functions that serialize and deserialize any Serde-compatible Rust type directly to and from CBOR bytes
  • An untyped Value enum (Null, Bool, Integer, Float, Bytes, Text, Array, Map, Tag) for inspecting or building CBOR documents whose schema isn’t known at compile time
  • A packed encoding mode (Serializer::packed_format) that replaces struct field names and unit-like enum variants with small integers to reduce wire size
  • no_std and alloc-only build configurations for embedded and resource-constrained targets, alongside slice-based readers/writers that avoid heap allocation
  • Zero-copy deserialization of borrowed strings and byte slices when decoding from an in-memory buffer

Common Use Cases

  • Persisting Rust structs to disk or a database column as a compact binary blob instead of JSON text
  • Encoding request/response payloads for RPC or IoT protocols where CBOR’s smaller size matters over constrained links
  • Implementing no_std firmware or embedded services that need a binary serialization format without a heap
  • Interoperating with other CBOR implementations (in other languages) via the RFC 7049 canonical wire format
  • Inspecting or transforming arbitrary CBOR documents at runtime using the untyped Value type before mapping them onto typed structs

Under The Hood

Architecture The crate splits cleanly along the Serde data-format seam: ser.rs implements serde::Serializer for a generic Serializer<W> parameterized over a Write trait (with IoWrite and SliceWrite adapters in write.rs for std::io::Write and fixed buffers respectively), while de.rs implements serde::Deserializer for a Deserializer<R> built over a matching Read trait defined in read.rs (SliceRead, MutSliceRead, IoRead) that abstracts over borrowing, mutable-slice, and reader-backed input. The optional value module (value/mod.rs, value/de.rs, value/ser.rs) layers an untyped Value enum on top of the same Serializer/Deserializer traits via its own to_value/from_value conversions, so typed and untyped paths share one encoding implementation rather than duplicating wire-format logic. tags.rs and error.rs are kept as separate concerns — tag handling behind a feature flag, and a single Error/ErrorCode type threaded through both directions — so the core read/write abstraction stays the one thing that would break every downstream module if changed.

Tech Stack The crate is pure Rust (edition 2018, MSRV 1.40) with exactly two runtime dependencies: serde (with default-features = false so std support is opt-in via the crate’s own std feature) and half for IEEE 754 half-precision float handling used by CBOR’s compact float encoding; serde_derive is a dev-dependency used only in doctests and tests. Cargo feature flags (std, alloc, unsealed_read_write, tags) gate functionality so the crate can build for no_std embedded targets like thumbv7em-none-eabihf, verified in CI via cargo build --no-default-features --features alloc --target thumbv7em-none-eabihf. There is no async runtime, no database layer, and no web framework involved — this is a leaf serialization library meant to be linked into other crates, with a fuzz/ directory wiring up cargo-fuzz for input-corpus fuzz testing.

Code Quality Testing is extensive relative to the crate’s size: roughly 82 #[test] functions across eight files in tests/ (de.rs, ser.rs, value.rs, enum.rs, canonical.rs, tags.rs, std_types.rs, bennofs.rs), covering round-trip encode/decode, canonical map ordering, enum representations, and regressions filed by outside contributors. CI (Travis) runs cargo fmt --all -- --check, cargo clippy -- -D clippy::all, the full test suite under both std and no_std/alloc configurations, and a fuzzing target — a notably thorough setup for a single-purpose crate. CONTRIBUTING.md explicitly asks contributors to add a test for every new feature or bug fix and states the project intentionally avoids unsafe code. Error handling is centralized through a typed Error/ErrorCode pair rather than string errors or panics on malformed input.

What Makes It Unique The standout design choice is dual-mode operation from one codebase: the same Serializer/Deserializer types serve both a fully-typed Serde path and an untyped Value-based path, and both work identically whether compiled with std, alloc-only, or bare no_std. The packed-encoding option (numeric field/variant tags instead of string keys) is a genuine size optimization specific to CBOR’s flexibility as a superset of the JSON data model, not something a JSON-based Serde format can offer. The project is archived and explicitly deprecated by its author in favor of ciborium and minicbor, so its innovation is now historical — it demonstrated the pattern that its recommended successors have since built on, rather than being the crate to reach for on a new project.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search