Welcome to Ciborium!
Ciborium contains CBOR serialization and deserialization implementations for serde.
You're probably looking for
ser::into_writer(), which are the main functions. Note that byte slices are also readers and writers and can be passed to these functions just as streams can.
For dynamic CBOR value creation/inspection, see
Although the CBOR specification has differing numeric widths, this is only a form of compression on the wire and is not intended to directly represent an “integer width” or “float width.” Therefore, ciborium always serializes numbers to the smallest possible lossless encoding. For example, we serialize
1u128 as a single byte (
01). Likewise, we will also freely decode that single byte into a
While there is some minor performance cost for this, there are several reasons for this choice. First, the specification seems to imply it by using a separate bit for the sign. Second, the specification requires that implementations handle leading zeroes; a liberal reading of which implies a requirement for lossless coercion. Third, dynamic languages like Python have no notion of “integer width,” making this is a practical choice for maximizing wire compatibility with those languages.
This coercion is always lossless. For floats, this implies that we only coerce to a smaller size if coercion back to the original size has the same raw bits as the original.
The ciborium project follows the Robustness Principle. Therefore, we aim to be liberal in what we accept. This implies that we aim to be wire-compatible with other implementations in decoding, but not necessarily encoding.
One notable example of this is that
serde_cbor uses fixed-width encoding of numbers and doesn't losslessly coerce. This implies that
ciborium will successfully decode
serde_cbor encodings, but the opposite may not be the case.
Other serde parsers have generally taken the route of using
HashMap to implement their encoding's underlying
Map type. This crate chooses to represent the
Map type using
Vec<(Value, Value)> instead.
This decision was made because this type preserves the order of the pairs on the wire. Further, for those that need the properties of
HashMap, you can simply
collect() the values into the respective type. This provides maximum flexibility.
The ciborium crate has the beginnings of a low-level library in the (private)
basic module. We may extend this to be more robust and expose it for application consumption once we have it in a good state. If you'd like to collaborate with us on that, please contact us. Alternatively, we might fork this code into a separate crate with no serde dependency.
The ciborium crate contains a number of internal types that implement useful serde traits. While these are not currently exposed, we might choose to expose them in the future if there is demand. Generally, this crate takes a conservative approach to exposing APIs to avoid breakage.
Packed encoding uses numerical offsets to represent structure field names and enum variant names. This can save significant space on the wire.
While the authors of this crate like packed encoding, it should generally be avoided because it can be fragile as it exposes invariants of your Rust code to remote actors. We might consider adding this in the future. If you are interested in this, please contact us.