#binary-encoding #serialization #binary-format #encode-decode #binary-data #no-std #data-model

no-std musli-storage

Partially upgrade stable format for Müsli suitable for storage

117 releases

0.0.117 Apr 20, 2024
0.0.108 Mar 30, 2024
0.0.94 Dec 12, 2023
0.0.91 Nov 13, 2023
0.0.37 May 27, 2022

#2268 in Encoding

Download history 1362/week @ 2024-07-21 1225/week @ 2024-07-28 440/week @ 2024-08-04 917/week @ 2024-08-11 568/week @ 2024-08-18 550/week @ 2024-08-25 1095/week @ 2024-09-01 289/week @ 2024-09-08 639/week @ 2024-09-15 316/week @ 2024-09-22 452/week @ 2024-09-29 705/week @ 2024-10-06 380/week @ 2024-10-13 377/week @ 2024-10-20 311/week @ 2024-10-27 696/week @ 2024-11-03

1,882 downloads per month
Used in 7 crates (5 directly)

MIT/Apache

1MB
22K SLoC

musli-storage

github crates.io docs.rs build status

Super simple storage encoding for Müsli

The storage encoding is partially upgrade safe:

  • ✔ Can tolerate missing fields if they are annotated with #[musli(default)].
  • ✗ Cannot skip over extra unrecognized fields.

This means that it's suitable as a storage format, since the data model only evolves in one place. But unsuitable as a wire format since it cannot allow clients to upgrade independent of each other.

See musli-wire for a fully upgrade safe format.

use musli::{Encode, Decode};

#[derive(Debug, PartialEq, Encode, Decode)]
struct Version1 {
    name: String,
}

#[derive(Debug, PartialEq, Encode, Decode)]
struct Version2 {
    name: String,
    #[musli(default)]
    age: Option<u32>,
}

let version2 = musli_storage::to_vec(&Version2 {
    name: String::from("Aristotle"),
    age: Some(62),
})?;

assert!(musli_storage::decode::<_, Version1>(version2.as_slice()).is_err());

let version1 = musli_storage::to_vec(&Version1 {
    name: String::from("Aristotle"),
})?;

let version2: Version2 = musli_storage::decode(version1.as_slice())?;

assert_eq!(version2, Version2 {
    name: String::from("Aristotle"),
    age: None,
});

Configuring

To tweak the behavior of the storage format you can use the Encoding type:

use musli::mode::Binary;
use musli::{Encode, Decode};
use musli_utils::options::{self, Options, Integer};
use musli_storage::Encoding;

const OPTIONS: Options = options::new().with_integer(Integer::Fixed).build();
const CONFIG: Encoding<OPTIONS> = Encoding::new().with_options();

#[derive(Debug, PartialEq, Encode, Decode)]
struct Struct<'a> {
    name: &'a str,
    age: u32,
}

let mut out = Vec::new();

let expected = Struct {
    name: "Aristotle",
    age: 61,
};

CONFIG.encode(&mut out, &expected)?;
let actual = CONFIG.decode(&out[..])?;

assert_eq!(expected, actual);

Dependencies

~0.4–0.9MB
~21K SLoC