Rust Serde Versioning
Serde is an amazing collection of Rust libraries for Serialization and Deserialization with many useful supported formats.
For example, I can convert a YAML file into a native Rust struct by just slapping a #[derive(Deserialize)]
above the struct.
One challenge that I faced was reading YAML files of different schema versions.
One option is to use Option<T>
for all fields which changed between versions. Generally speaking, this is probably the easiest and most suitable solution. However, when parsing is also used as a linter, this will not suffice. For example, we might have a version 1.0 that has fields a
and b
(both required). In version 2.0, only a
remains and b
is replaced by c
.
To solve this, I found that tagged enums make for the best representation.
Here’s an example input file:
my_version: 1.0
a: "bla"
b: "blub"
Here’s the MyFile enum, internally tagged on the field my_version
:
#[derive(Debug, Deserialize)]
#[serde(tag = "my_version")]
enum MyFile {
#[serde(rename = "1.0")]
V1(MyFileV1),
#[serde(rename = "2.0")]
V2(MyFileV2),
}
And the MyFileV1
looks like this:
#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
struct MyFileV1 {
a: String,
b: String,
}
You can see a free standing example here on the Rust playground.