interface 0.0.3

Typed, lossy-aware interface translation between API versions
Documentation
  • Coverage
  • 100%
    21 out of 21 items documented2 out of 19 items with examples
  • Size
  • Source code size: 13.46 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 2.43 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 16s Average build duration of successful builds.
  • all releases: 18s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • Tim-Raphael/interface
    0 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • Tim-Raphael

interface (WIP)

Typed, lossy-aware interface translation between API versions.

Overview

interface models data migration between versioned API schemas. Each conversion is a [Translation<Source, Target, Lossiness>] — a deferred, inspectable value that carries a [Diff] and encodes at the type level whether the conversion is information-preserving ([Lossless]) or destructive ([Lossy]).

Usage

Implement Upgrade / Downgrade

use interface::{Diff, Lossless, Lossy, Translation, Upgrade, Downgrade};

mod v1 {
    #[derive(Debug, PartialEq, Eq)]
    pub struct User { pub name: String }
}

mod v2 {
    #[derive(Debug, PartialEq, Eq)]
    pub struct User { pub name: String, pub email: String }
}

impl Upgrade<v2::User> for v1::User {
    type Lossiness = Lossless;

    fn upgrade(self) -> Translation<Self, v2::User, Lossless> {
        let diff = Diff::new().add("email", "default@example.com");
        Translation::new(self, Box::new(|s| v2::User {
            name: s.name,
            email: "default@example.com".into(),
        }), diff)
    }
}

impl Downgrade<v1::User> for v2::User {
    type Lossiness = Lossy;

    fn downgrade(self) -> Translation<Self, v1::User, Lossy> {
        let diff = Diff::new().sub("email", &self.email);
        Translation::new(self, Box::new(|s| v1::User { name: s.name }), diff)
    }
}

Execute a translation

// Lossless: `.translate()` is only available on `Translation<_, _, Lossless>`
let t = v1::User { name: "Alice".into() }.upgrade();
assert!(!t.is_lossy());
let v2_user = t.translate();

// Lossy: must call `.translate_lossy()` — the distinct method name forces acknowledgement
let t = v2_user.downgrade();
assert!(t.is_lossy());
println!("{t}");             // prints the diff
let v1_user = t.translate_lossy();

License

MIT