#derive #cbor

macro cbored-derive

CBOR exact reader and writer (CborRepr derive macro)

4 releases (2 breaking)

0.3.2 Dec 22, 2023
0.3.1 Aug 18, 2022
0.2.0 Aug 16, 2022
0.1.0 Apr 26, 2022

#57 in #cbor

Download history 39/week @ 2023-10-21 98/week @ 2023-10-28 46/week @ 2023-11-04 88/week @ 2023-11-11 61/week @ 2023-11-18 159/week @ 2023-11-25 103/week @ 2023-12-02 76/week @ 2023-12-09 118/week @ 2023-12-16 114/week @ 2023-12-23 33/week @ 2023-12-30 94/week @ 2024-01-06 57/week @ 2024-01-13 28/week @ 2024-01-20 110/week @ 2024-01-27 22/week @ 2024-02-03

223 downloads per month
Used in 3 crates (via cbored)

MIT/Apache

60KB
1.5K SLoC

cbored - Exact CBOR

cbored is a CBOR reader and writer, focused on exact 1-1 CBOR representation.

Design decision

This CBOR crate is based on the following decisions:

  • Keep close to the CBOR types
  • Able to recover the exact bytes of a given encoded CBOR type, specially in the case of non-canonical CBOR use
  • Hide the indefinite/definite possible options in given CBOR types to keep usage simple

The main use cases is to deal with CBOR data stream that are not requiring one canonical given representation (standard CBOR canonical or another) and when the data serialized need to be kept as is (e.g. when used in cryptographic settings)

Caveat Emptor

  • signed integer are not particularly well supported, due to not being used in my use cases, so there's quite a few missing conversion; contribution welcome

Auto CBOR Encode and Decode derive

Automatic proc-macro derive can be enabled in the Cargo.toml:

cbored = { version = "0.1", features = ["derive"] }

Which allow to derive Decode and Encode implementation for enum and struct types:

#[derive(CborRepr)]
#[cborrepr(structure = "array")]
// serialized as : ARRAY(2) [UINT, UINT]
pub struct Point {
    x: u32,
    y: u32,
}

#[derive(CborRepr)]
#[cborrepr(structure = "array_lastopt")]
// serialized as : ARRAY(2) [UINT, UINT]
//            or : ARRAY(1) [UINT]
pub struct Point {
    x: u32,
    y: Option<u32>,
}

#[derive(CborRepr)]
#[cborrepr(structure = "flat")]
// serialized as : UINT, UINT
pub struct FlatPoint {
    x: u32,
    y: u32,
}

#[derive(CborRepr)]
#[cborrepr(structure = "mapint")]
// serialized as : MAP(2) { UINT(0) => UINT, UINT(1) => UINT }
//            or : MAP(3) { UINT(0) => UINT, UINT(1) => UINT, UINT(2) => UINT }
pub struct FlatPoint {
    #[cborrepr(mandatory)]
    x: u32,
    #[cborrepr(mandatory)]
    y: u32,
    z: Option<u32>
}

#[derive(CborRepr)]
#[cborrepr(enumtype = "tagvariant")]
// serialized as
// * One : ARRAY(2) [ UINT(0), ARRAY(2) [UINT, UINT] ]
// * Two : ARRAY(3) [ UINT(1), ARRAY(2) [UINT, UINT], ARRAY(2) [UINT, UINT] ]
pub enum Variant {
    One(Point),
    Two(Point, Point),
}

#[derive(CborRepr)]
#[cborrepr(enumtype = "enumint")]
// serialized as
// * Code1 : UINT(0)
// * Code2 : UINT(1)
// * Code3 : UINT(2)
pub enum Code {
    Code1,
    Code2,
    Code3,
}

#[derive(CborRepr)]
#[cborrepr(enumtype = "enumtype")]
// serialized as
// * Empty : NULL
// * One   : UINT
pub enum OneOrEmpty {
    #[cborrepr(cbortype = "null")]
    Empty,
    #[cborrepr(cbortype = "positive")]
    One(u64),
}

Structure:

  • array: the structure is serialized one after another inside an array of the length reflecting the number of elements
  • flat: each field is serialized one after another, using the Decode/Encode instance of each type. not recommended in general case, as it doesn't play nice with array / map structure.

Enums :

  • tagvariant: array with a leading integer representing the variant, following by any fields in the
  • enumint: just an integer for variant with no inner element. integer is sequentially incremented between variant, and starts at 0

Dependencies

~1.5MB
~32K SLoC