I would like to make sure that different versions of my serialized type can be deserialized into the appropriate version of the type. The goal is to facilitate migration between versions.
What follows might be an instantiation of the XY problem.
One idea is to include a version tag as a field and allow matching against this tag. I think this requires wrapping the serialized type and a stable wrapper type.
struct VersionedMyStruct {
version: u32,
serialized_my_struct: Vec<u8>,
}
struct MyStruct { /* … */ }
type OldStruct = same_crate_old_version::MyStruct;
fn main() -> Result<(), _> {
let versioned_struct = VersionedMyStruct::deserialize(/* … */)?;
let serialized = versioned_struct.serialized_my_struct;
let my_struct = match versioned_struct.version {
0 => MyStruct::from(OldStruct::deserialize(serialized)?),
1 => MyStruct::deserialize(serialized)?,
v => return Err(UnknownVersion(v)),
};
}
Another idea is to have a version
field in the struct itself and fail deserialization with a specific error if its value is not as expected.
const CURRENT_VERSION: u32 = 1;
struct MyStruct {
version: u32,
/* … */
}
impl Deserialize for MyStruct {
fn deserialize(data: &[u8]) -> Result<Self, _> {
/* … */
if the_version != CURRENT_VERSION {
return Err(IncorrectVersion);
}
/* … */
}
}
type OldStruct = same_crate_old_version::MyStruct;
fn main() -> Result<(), _> {
let serialized = data_from_somewhere();
let my_struct = match MyStruct::deserialize(serialized) {
Ok(my_struct) => my_struct,
Err(IncorrectVersion) => MyStruct::from(OldStruct::deserialize(serialized)?),
_ => return Err(UnknownVersion),
};
}
Both of these ideas feel somewhat clunky. This is partly because my_crate
depends on old versions of itself in both ideas. Also, versioning is manual, and I'm not sure how I can reliably detect whether the version must be bumped. Keeping track of which versions of the type can be migrated, and how to do so, is probably a necessary burden.
Are there standard solutions for scenarios like these? A pattern, a crate, a serde feature? Are the sketched ideas approaching the mark, or am I completely off target? Happy about any & all feedback & ideas.