frozone 0.1.0

Freeze structs and enums in time
Documentation

frozone

frozone is a crate that allows you to 'freeze' structs and enums recursively to ensure they never get changed, helping enforcing backwards-compatibility or API stability (arewesemveryet.org ?)

Use case

Let's say there is a very important data structure for your application:

#[derive(Serialize, Deserialize)]
struct Frozone {
    power: Power,
    equipment: Vec<Part>,
    super_suit: Suit
}

#[derive(Serialize, Deserialize)]
enum Part {
    Sunglasses,
    Skates,
    //...
}

that gets serialized in ~/.config/frozone/state.json on each user's machine. You've released v1 and everyone is happy.

However, for v2, you realize that you would prefer super_suit to be included in equipment instead. Good, but now, whenever your v2 program runs and tries to load a 'v1' config, your deserializer will rightfully tell you: Honey, where's my super_suit ?

You probably know that the answer to this backward-compatibility issue is to add a version field, save the old structure tree somewhere, and create new ones

struct FrozoneV2 {
    version: String,
    power: Power,
    equipments: Vec<PartV2>
}

impl From<Frozone> for FrozoneV2 {
    fn from(value: Frozone) -> FrozoneV2 {
        // ..proper migration code
    }
}

Of course, you'll never forget to check that no similar changes during the v1->v2 development have affected Power: a deeply-nested struct, with enough optional fields to make coverage testing a full-on PhD thesis, spanning multiple modules/crates/developer's responsibilities.

OF COURSE, RIGHT ?

frozone enforces your 'object tree' semantically never changes, ensuring serialization and API stability.

Usage

use frozone::Freezable;

#[derive(Serialize, Deserialize, Freezable)]
struct Frozone {
    power: Power,
    equipment: Vec<Part>,
    super_suit: Suit
}

#[derive(Serialize, Deserialize, Freezable)]
struct Power {
    // ...
}
// ...

fn main() {
    /// call the associated method `::freeze()` on your structure, and
    /// compare it to the fixed value it evaluated to
    assert_eq!(Frozone::freeze(),  12298013273002774775); // frozone hash from v1 release
    /// .. okay, `Frozone` has not changed since v1
}

Roadmap

  • structs support
  • clearly define what's included in the hash (struct name?)
  • enums support
  • compile-time check