Serde version
Serde version
//!
Versioning support for serde.
//!
When software are developped and used at the same time the data formats may change
from one version to another and persisting data may be produced by a specific version
and loaded by another version.
//!
Serde version provide a versioning feature for serde for the main use cases.
//!
Note 1: Requires the specialization feature.
Note 2: Use the derive
feature to generate the DeserializeVersioned
implementation
//!
Goals of Serde version
//!
We aim at solving the case were a type or a set of types in a deserializer's
data needs to be upgraded to their latest format.
This is the case when a mandatory property was added or removed,
or an existing property changed.
//!
Note: There already is support for added optional properties in serde.
(Use the default
feature of serde)
//!
Example:
Let's have a file containing these structure with those version number:
A: 1, B: 1, C: 2
and the current version numbers are: A: 3, B: 2, C: 4
.
//!
Then in latest code version, we have the former data structures versions,
let's call them: Av1
, Av2
, Bv1
, Cv1
, Cv2
, Cv3
.
//!
Deserializing, whenever a structure A
, B
or C
is ran into,
then it is loaded with the appropriate format (in our case it will be Av1
, Bv1
and Cv2
)
and then converted to A
, B
or C
using the From trait.
//!
Non goals
//!
This is based on types that can be upgraded individually.
Types that needs to be upgraded together is way more complex to handle
and usually relies on domain specific deserializer.
//!
So, these data format should be handle with specific Deserialize
traits implementations.
//!
Unsupported Serde feature with versioning
//!
deserialize_in_place
is not supported
//! Deserializing in place with versioning support is way more complicated, so we don't deal with this in this crate. //!
Not supported with deserialize_with
callback
//! You must take care of the versioning in your callback //!
Versioning is only supported for structs and enums
//! There is no use case where versioning tuples and the unit type is useful. //!
Usage
//!
To describe the previous versions of a type, we use the #[versions(...)]
attribute along with
the DeserializeVersioned
trait.
//!
Authoring example:
// Version 1 of struct A
// It must implement Deserialize, so it can be loaded by serde
// It must be identified by A during deserialization
//!
// Current version of struct A
// It must implement Deserialize and DeserializeVersioned
// We use the versions attribute to define the previous versions
// So, Version n°1 of A is Av1, Versions n°2 (current) of A is A
//!
// A must implement From for all previous type, so we implement From<Av1>
//! To perform the deserialization with the versioning support, we need to do two steps:
- Get the
VersionMap
which holds the version number to use per type - Call the
deserialize_versioned
method with theVersionMap
//! Note: The id used to find the version number of a type during deserialization is the deserialization name of the type. //! Execution example:
#
#
#
# extern crate serde_version_derive;
#
# use Deserialize;
# use Debug;
#
#
#
#
#
#
#
#
//!
//!
// Use ron as data format for this example
use ron;
use DeserializeVersioned;
//!
//!
VersionedDeserializer
//!
Under the hood, deserialize_version
wraps the provided deserializer with
the VersionedDeserializer
to support the versioning.
//!
Versioned groups
//!
A version group is a set of types with their associated version.
It is often easier to use a version number for multiple types together.
//!
You can refer to a version group by a VersionGroupURI
, this is an identifier used to select
the appropriate VersionMap
to use.
//!
The VersionGroupResolver
trait is then used to get the VersionMap
associated to a VersionGroupURI
.
//!
You can easily create version group resolver, uris and maps with the provided macros.
//!
Example:
version_group_resolver_static!
//!
// Define an enum to have an easy way to get the version uris
version_group_enum!
//!
use deserialize_test;
//!
// V1
deserialize_test;
deserialize_test;
deserialize_test;
//!
Use the example versioned_groups
to see it in action.