versionize/
lib.rs

1// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3#![deny(missing_docs, missing_debug_implementations)]
4
5//! Defines a generic interface for version tolerant serialization and
6//! implements it for primitive data types using `bincode` as backend.
7//!
8//! The interface has two components:
9//! - `Versionize` trait
10//! - `VersionMap` helper
11//!
12//! `VersionMap` maps individual structure/enum versions to a root version
13//! (app version). This mapping is required both when serializing or
14//! deserializing structures as it needs to know which version of structure
15//! to serialize for a given target app version.
16//!
17//! `Versionize` trait is implemented for the following primitives:
18//! u8, u16, u32, u64, usize, i8, i16, i32, i64, isize, char, f32, f64,
19//! String, Vec<T>, Arrays up to 32 elements, Box<T>, Wrapping<T>, Option<T>,
20//! FamStructWrapper<T>, and (T, U).
21//!
22//! Known issues and limitations:
23//! - Union serialization is not supported via the `Versionize` proc macro.
24//! - Implementing `Versionize` for non-repr(C) unions can result in undefined
25//! behaviour and MUST be avoided.
26//! - Versionize trait implementations for repr(C) unions must be backed by
27//! extensive testing.
28//! - Semantic serialization and deserialization is available only for
29//! structures.
30extern crate bincode;
31extern crate crc64;
32extern crate serde;
33extern crate serde_derive;
34extern crate versionize_derive;
35extern crate vmm_sys_util;
36
37pub mod crc;
38pub mod primitives;
39pub mod version_map;
40
41use std::any::TypeId;
42use std::io::{Read, Write};
43pub use version_map::VersionMap;
44use versionize_derive::Versionize;
45
46/// Versioned serialization/deserialization error definitions.
47#[allow(clippy::derive_partial_eq_without_eq)] // FIXME: next major release
48#[derive(Debug, PartialEq)]
49pub enum VersionizeError {
50    /// An IO error occured.
51    Io(i32),
52    /// Generic serialization error.
53    Serialize(String),
54    /// Generic deserialization error.
55    Deserialize(String),
56    /// Semantic translation/validation error.
57    Semantic(String),
58    /// String length exceeded.
59    StringLength(usize),
60    /// Vector length exceeded.
61    VecLength(usize),
62}
63
64impl std::fmt::Display for VersionizeError {
65    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
66        use VersionizeError::*;
67
68        match self {
69            Io(e) => write!(f, "An IO error occured: {}", e),
70            Serialize(e) => write!(f, "A serialization error occured: {}", e),
71            Deserialize(e) => write!(f, "A deserialization error occured: {}", e),
72            Semantic(e) => write!(f, "A user generated semantic error occured: {}", e),
73            StringLength(bad_len) => write!(
74                f,
75                "String length exceeded {} > {} bytes",
76                bad_len,
77                primitives::MAX_STRING_LEN
78            ),
79            VecLength(bad_len) => write!(
80                f,
81                "Vec of length {} exceeded maximum size of {} bytes",
82                bad_len,
83                primitives::MAX_VEC_SIZE
84            ),
85        }
86    }
87}
88
89/// Versioned serialization/deserialization result.
90pub type VersionizeResult<T> = std::result::Result<T, VersionizeError>;
91
92/// Trait that provides an interface for version aware serialization and
93/// deserialization.
94/// The [Versionize proc macro][1] can generate an implementation for a given
95/// type if generics are not used, otherwise a manual implementation is
96/// required.
97///
98/// Example implementation
99/// ```
100/// extern crate versionize;
101/// extern crate versionize_derive;
102/// use versionize::{VersionMap, Versionize, VersionizeResult};
103/// use versionize_derive::Versionize;
104///
105/// struct MyType<T>(T);
106///
107/// impl<T> Versionize for MyType<T>
108/// where
109///     T: Versionize,
110/// {
111///     #[inline]
112///     fn serialize<W: std::io::Write>(
113///         &self,
114///         writer: &mut W,
115///         version_map: &VersionMap,
116///         app_version: u16,
117///     ) -> VersionizeResult<()> {
118///         self.0.serialize(writer, version_map, app_version)
119///     }
120///
121///     #[inline]
122///     fn deserialize<R: std::io::Read>(
123///         reader: &mut R,
124///         version_map: &VersionMap,
125///         app_version: u16,
126///     ) -> VersionizeResult<Self> {
127///         Ok(MyType(T::deserialize(reader, version_map, app_version)?))
128///     }
129///
130///     fn version() -> u16 {
131///         1
132///     }
133/// }
134/// ```
135/// [1]: https://docs.rs/versionize_derive/latest/versionize_derive/derive.Versionize.html
136pub trait Versionize {
137    /// Serializes `self` to `target_verion` using the specficifed `writer` and
138    /// `version_map`.
139    fn serialize<W: Write>(
140        &self,
141        writer: &mut W,
142        version_map: &VersionMap,
143        target_version: u16,
144    ) -> VersionizeResult<()>;
145
146    /// Returns a new instance of `Self` by deserializing from `source_version`
147    /// using the specficifed `reader` and `version_map`.
148    fn deserialize<R: Read>(
149        reader: &mut R,
150        version_map: &VersionMap,
151        source_version: u16,
152    ) -> VersionizeResult<Self>
153    where
154        Self: Sized;
155
156    /// Returns the `Self` type id.
157    /// The returned ID represents a globally unique identifier for a type.
158    /// It is required by the `VersionMap` implementation.
159    fn type_id() -> std::any::TypeId
160    where
161        Self: 'static,
162    {
163        TypeId::of::<Self>()
164    }
165
166    /// Returns latest `Self` version number.
167    fn version() -> u16;
168}
169
170#[cfg(test)]
171mod tests {
172    #[test]
173    fn test_error_debug_display() {
174        // Validates Debug and Display are implemented.
175        use VersionizeError::*;
176        let str = String::from("test");
177        format!("{:?}{}", Io(0), Io(0));
178        format!("{:?}{}", Serialize(str.clone()), Serialize(str.clone()));
179        format!("{:?}{}", Deserialize(str.clone()), Deserialize(str.clone()));
180        format!("{:?}{}", Semantic(str.clone()), Semantic(str));
181    }
182}