[![Workflow Status](https://github.com/enarx/ciborium/workflows/test/badge.svg)](https://github.com/enarx/ciborium/actions?query=workflow%3A%22test%22)
[![Average time to resolve an issue](https://isitmaintained.com/badge/resolution/enarx/ciborium.svg)](https://isitmaintained.com/project/enarx/ciborium "Average time to resolve an issue")
[![Percentage of issues still open](https://isitmaintained.com/badge/open/enarx/ciborium.svg)](https://isitmaintained.com/project/enarx/ciborium "Percentage of issues still open")
![Maintenance](https://img.shields.io/badge/maintenance-activly--developed-brightgreen.svg)

# ciborium

Welcome to Ciborium!

Ciborium contains CBOR serialization and deserialization implementations for serde.

## Quick Start

You're probably looking for [`de::from_reader()`](crate::de::from_reader)
and [`ser::into_writer()`](crate::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 [`value::Value`](crate::value::Value).

## Design Decisions

### Always Serialize Numeric Values to the Smallest Size

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 `u128`.

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.

### Compatibility with Other Implementations

The ciborium project follows the [Robustness Principle](https://en.wikipedia.org/wiki/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.

### Representing Map as a Sequence of Values

Other serde parsers have generally taken the route of using `BTreeMap` or
`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 `BTreeMap` or
`HashMap`, you can simply `collect()` the values into the respective type.
This provides maximum flexibility.

### Low-level Library

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.

### Internal Types

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?

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.

License: Apache-2.0
