Crate obake

source ·
Expand description

Obake

Obake is a procedural macro for declaring and maintaining versioned data-structures. The name ‘obake’ is taken from the Japanese ‘お化け (おばけ)’, a class of supernatural beings in Japanese folklore that shapeshift.

When developing an application, configuration formats and internal data-structures typically evolve between versions. However, maintaining backwards compatibility between these versions requires declaring a maintaining data-structures for legacy formats and code for migrating between them. Obake aims to make this process effortless.

Example

#[obake::versioned]                 // create a versioned data-structure
#[obake(version("0.1.0"))]          // declare some versions
#[obake(version("0.2.0"))]
#[derive(Debug, PartialEq, Eq)]     // additional attributes are applied to all versions
struct Foo {
    #[obake(cfg("0.1.0"))]          // enable fields for specific versions with
    foo: String,                    // semantic version constraints
    
    #[obake(cfg(">=0.2, <=0.3.0"))] // any semantic version constraint can appear in
    bar: u32,                       // a `cfg` attribute
    
    #[obake(cfg("0.1.0"))]          // multiple `cfg` attributes are treated as a
    #[obake(cfg(">=0.3"))]          // disjunction over version constraints
    baz: char,
}

// describe migrations between versions using the `From` trait
// and an automatically generated type-level macro for referring to
// specific versions of `Foo`
impl From<Foo!["0.1.0"]> for Foo!["0.2.0"] {
    fn from(foo: Foo!["0.1.0"]) -> Self {
        Self { bar: 0 }
    }
}

// an enumeration of all versions of `Foo` is accessed using the `obake::AnyVersion` type
// alias
let versioned_example: obake::AnyVersion<Foo> = (Foo { bar: 42 }).into();

// this enumeration implements `Into<Foo>`, where `Foo` is the latest declared
// version of `Foo` (in this case, `Foo!["0.2.0"]`)
let example: Foo = versioned_example.into();

assert_eq!(example, Foo { bar: 42 });

Other Features

  • #[obake(inherit)]: allows nesting of versioned data-structures.
  • #[obake(derive(...))]: allows derive attributes to be applied to generated enums.
  • #[obake(serde(...))]: allows serde attributes to be applied to generated enums.
    • Note: requires the feature serde.

Limitations

  • Cannot be applied to tuple structs (or enum variants with unnamed fields).
  • Cannot be applied to items with generic parameters.

Structs

Traits

  • Automatically implemented for all declared versions of a versioned data-structure.
  • Automatically implemented by the generated version-tagged encoding of a versioned data-structure.
  • Automatically implemented for the latest version of a versioned data-structure.

Type Definitions

  • Short-hand for referring to the version-tagged representation of a versioned data-structre.

Attribute Macros

  • The core macro of the library. Used to declare versioned data-structures.