Derive Macro versionize_derive::Versionize
source · #[derive(Versionize)]
{
// Attributes available to this derive:
#[version]
}
Expand description
Generates serialization and deserialization code as an implementation of
the Versionize
trait.
Different code paths are generated for each version of the structure or enum. There is no limit enforced on the maximum number of structure versions.
Struct and enum requirements
- all members or enum variants need to implement the
Versionize
trait - no generics are being used (this is currenly a limitation)
Annotations
To facilitate version tolerant serialization “history metadata” is attached
to the structure or enum. This is done by using the version
attribute in
their definition. In the below example a new field is added to the
structure starting with version 2: #[version(start = 2)]
.
extern crate versionize;
extern crate versionize_derive;
use versionize::{Versionize, VersionizeError, VersionizeResult};
use versionize_derive::Versionize;
#[derive(Versionize)]
struct Test {
a: u32,
#[version(start = 2)]
b: u8,
}
Multiple version annotations can be defined for a field, like for example:
#[version(start = 2, end = 3)]
. Field was added in structure version 2
and removed in version 3. The generated code will attempt to (de)serialize
this field only for version 2 of the structure.
Supported field attributes and usage
The version
attribute accepts multiple key/value pairs to be specified in
order to support versioning, semantic serialization and default values for
fields. All of these are optional and a default behaviour is provided in
their absence.
default_fn
Provides an initialization value for a field when deserializing from an
older structure version which does not contain this field. If not specified
the Default
trait isused to initialize the field.
extern crate versionize;
extern crate versionize_derive;
use versionize::{Versionize, VersionizeError, VersionizeResult};
use versionize_derive::Versionize;
#[derive(Versionize)]
struct TestStruct {
a: u32,
#[version(start = 2, default_fn = "default_b")]
b: u8,
}
impl TestStruct {
fn default_b(_source_version: u16) -> u8 {
12u8
}
}
The function name needs to be specified as a string and its prototype must take an u16 source version parameter and return a value of the same type as as the field.
start/end
Defines the field version lifetime. Fields can be added by specifing the start version of the structure when first defining them and can be later on removed from serialization logic by adding and end version.
For example: #[version(start = 2, end = 4)]
. The field would be present
in the structure v2 and v3, but starting with v4 it would no longer be
serialized or deserialized.
Once a field is removed, it can never be added again in a future version.
ser_fn
- Not supported for enums. *
Defines a semantic serialization function for a field. The function needs
to be specified as a string and implemented as a method attached to
the structure. The prototype of the function is
fn(&mut self, u16) -> VersionizeResult<()>
.
If defined, the method is called when the field is skipped from
serialization because it does not exist in the target version of the
structure. Its implementation can perform any mutation of self
or return
an error to stop serialization. Intended usage is to implement semantic
translation or semantic validations.
extern crate versionize;
extern crate versionize_derive;
use versionize::{Versionize, VersionizeError, VersionizeResult};
use versionize_derive::Versionize;
#[derive(Versionize)]
struct SomeStruct {
some_u32: u32,
#[version(start = 2, ser_fn = "ser_u16")]
some_u16: u16,
}
impl SomeStruct {
fn ser_u16(&mut self, target_version: u16) -> VersionizeResult<()> {
self.some_u32 = self.some_u32 & self.some_u16 as u32;
Ok(())
}
}
de_fn
- Not supported for enums. *
Defines a semantic deserialization function for a field. The function needs
to be specified as a string and implemented as a method attached to
the structure. The prototype of the function is
fn(&mut self, u16) -> VersionizeResult<()>
.
If defined, the method is called if the field is skipped from
deserialization because it does not exist in the source version of the
serialized structure. Its implementation can perform any mutation of self
or return an error to stop deserialization. Intended usage is to implement
semantic translation or semantic validations.
Both default_fn
and de_fn
can be specified for a field. default_fn
is
always called first and de_fn
last.
extern crate versionize;
extern crate versionize_derive;
use versionize::{Versionize, VersionizeError, VersionizeResult};
use versionize_derive::Versionize;
#[derive(Clone, Versionize)]
struct SomeStruct {
some_u32: u32,
#[version(start = 2, ser_fn = "ser_u16", de_fn = "de_u16")]
some_u16: u16,
}
impl SomeStruct {
fn ser_u16(&mut self, target_version: u16) -> VersionizeResult<()> {
self.some_u32 = self.some_u32 & self.some_u16 as u32;
Ok(())
}
fn de_u16(&mut self, source_version: u16) -> VersionizeResult<()> {
if source_version < 2 {
self.some_u16 = (self.some_u32 & 0xFF) as u16;
}
Ok(())
}
}