[][src]Crate minicbor_derive

Procedural macros to derive minicbor's Encode and Decode traits.

Deriving is supported for structs and enums. The encoding is optimised for forward and backward compatibility and the overall approach is influenced by Google's Protocol Buffers.

The goal is that ideally a change to a type still allows older software, which is unaware of the changes, to decode values of the changed type (forward compatibility) and newer software, which knows about the changes, to decode values of types which have been encoded by older software and which therefore do not include the changes made to the type (backward compatibility).

In order to reach this goal the encoding has the following characteristics:

  1. The encoding does not contain any names, i.e. no field names, type names or variant names. Instead every field and every constructor needs to be annotated with an (unsigned) index number, e.g. #[n(1)].

  2. Unknown fields are ignored during decoding.

  3. Optional types default to None if their value is not present during decoding.

  4. Optional enums default to None if an unknown variant is encountered during decoding.

Item 1. ensures that names can be changed freely without compatibility concerns. Item 2. ensures that new fields do not affect older software. Item 3. ensures that newer software can stop producing optional values. Item 4. ensures that enums can get new variants that older software is not aware of. By "fields" we mean the elements of structs and tuple structs well as enum structs and enum tuples. In addition it is a compatible change to turn a unit variant into a struct or tuple variant if all fields are optional.

From the above it should be obvious that non-optional fields need to be present forever, so they should only be part of a type after careful consideration.

It should be emphasised that an enum itself can not be changed in a compatible way. An unknown variant causes an error. It is only when they are declared as an optional field type that unknown variants of an enum are mapped to None. In other words, only structs can be used as top-level types in a forward and backward compatible way, enums can not.

Example

use minicbor::{Encode, Decode};

#[derive(Encode, Decode)]
struct Point {
    #[n(0)] x: f64,
    #[n(1)] y: f64
}

#[derive(Encode, Decode)]
struct ConvexHull {
    #[n(0)] left: Point,
    #[n(1)] right: Point,
    #[n(2)] points: Vec<Point>,
    #[n(3)] state: Option<State>
}

#[derive(Encode, Decode)]
enum State {
    #[n(0)] Start,
    #[n(1)] Search { #[n(0)] info: u64 }
}

In this example the following changes would be compatible in both directions:

  • Renaming every identifier.

  • Adding optional fields to Point, ConvexHull, State::Start or State::Search.

  • Adding more variants to State iff State is only decoded as part of ConvexHull. Direct decoding of State would produce an UnknownVariant error for those new variants.

Derive Macros

Decode

Derive the minicbor::Decode trait for a struct or enum.

Encode

Derive the minicbor::Encode trait for a struct or enum.