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}