#![allow(clippy::missing_safety_doc)]
extern crate versionize;
extern crate versionize_derive;
extern crate vmm_sys_util;
use std::fmt::{Debug, Formatter, Result};
use std::num::Wrapping;
use vmm_sys_util::fam::{FamStruct, FamStructWrapper};
use vmm_sys_util::generate_fam_struct_impl;
use versionize::{VersionMap, Versionize, VersionizeError, VersionizeResult};
use versionize_derive::Versionize;
#[derive(Debug, PartialEq, Versionize, Eq)]
pub enum TestState {
Zero,
One(u32),
#[version(start = 2, default_fn = "default_state_two")]
Two(u64),
}
impl TestState {
fn default_state_two(&self, target_version: u16) -> VersionizeResult<TestState> {
match target_version {
1 => Ok(TestState::One(2)),
i => Err(VersionizeError::Serialize(format!(
"Unknown target version: {}",
i
))),
}
}
}
#[test]
fn test_hardcoded_struct_deserialization() {
#[rustfmt::skip]
let v1_hardcoded_snapshot: &[u8] = &[
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
0xCD, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x50, 0x40, 0x61,
0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x73, 0x6F, 0x6D, 0x65, 0x5F, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67,
0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x01, 0x81,
0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x6F, 0x6D, 0x65, 0x5F,
0x6F, 0x74, 0x68, 0x65, 0x72, 0x5F, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67,
];
#[rustfmt::skip]
let v2_hardcoded_snapshot: &[u8] = &[
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00,
0xCD, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x20, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x50, 0x40, 0x61,
0x01,
0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x73, 0x6F, 0x6D, 0x65, 0x5F, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67,
0x02, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x81,
0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x6F, 0x6D, 0x65, 0x5F,
0x6F, 0x74, 0x68, 0x65, 0x72, 0x5F, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67,
];
#[rustfmt::skip]
let v3_hardcoded_snapshot: &[u8] = &[
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00,
0xFF, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x50, 0x40, 0x61,
0x01,
0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x73, 0x6F, 0x6D, 0x65, 0x5F, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67,
0x02, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x81,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x61, 0x61, 0x61,
0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x6F, 0x6D, 0x65, 0x5F,
0x6F, 0x74, 0x68, 0x65, 0x72, 0x5F, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67,
0xFF, 0x00, 0x00, 0x00,
];
#[rustfmt::skip]
let v4_hardcoded_snapshot: &[u8] = &[
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00,
0xFF, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x50, 0x40, 0x61,
0x01,
0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x73, 0x6F, 0x6D, 0x65, 0x5F, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67,
0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x81,
0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x6F, 0x6D, 0x65, 0x5F,
0x6F, 0x74, 0x68, 0x65, 0x72, 0x5F, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67,
0xFF, 0x00, 0x00, 0x00,
];
#[derive(Debug, PartialEq, Versionize)]
pub struct TestStruct {
usize_1: usize,
#[version(start = 2, end = 4, default_fn = "default_isize")]
isize_1: isize,
u16_1: u16,
#[version(end = 3, default_fn = "default_u64")]
u64_1: u64,
i8_1: i8,
#[version(start = 2, end = 2)]
i16_1: i16,
i32_1: i32,
#[version(start = 2, end = 3, default_fn = "default_i64")]
i64_1: i64,
f32_1: f32,
f64_1: f64,
char_1: char,
#[version(start = 2, default_fn = "default_bool")]
bool_1: bool,
string_1: String,
enum_1: TestState,
option_1: Option<u8>,
#[version(start = 3, end = 4, default_fn = "default_vec")]
vec_1: Vec<char>,
#[allow(clippy::box_collection)] box_1: Box<String>,
#[version(start = 3)]
wrapping_1: Wrapping<u32>,
}
impl TestStruct {
fn default_isize(_source_version: u16) -> isize {
12isize
}
fn default_u64(_source_version: u16) -> u64 {
0x0Du64
}
fn default_i64(_source_version: u16) -> i64 {
0x0Ei64
}
fn default_bool(_source_version: u16) -> bool {
false
}
fn default_vec(_source_version: u16) -> Vec<char> {
vec!['v'; 8]
}
}
let mut vm = VersionMap::new();
vm.new_version()
.set_type_version(TestStruct::type_id(), 2)
.set_type_version(TestState::type_id(), 2)
.new_version()
.set_type_version(TestStruct::type_id(), 3)
.new_version()
.set_type_version(TestStruct::type_id(), 4);
let mut snapshot_blob = v1_hardcoded_snapshot;
let mut restored_state =
<TestStruct as Versionize>::deserialize(&mut snapshot_blob, &vm, 1).unwrap();
let mut expected_state = TestStruct {
usize_1: 1,
isize_1: 12,
u16_1: 4,
u64_1: 0xABCDu64,
i8_1: -1,
i16_1: 0,
i32_1: 32,
i64_1: 0x0Ei64,
f32_1: 0.5,
f64_1: 64.5,
char_1: 'a',
bool_1: false,
string_1: "some_string".to_owned(),
enum_1: TestState::One(2),
option_1: Some(129),
vec_1: vec!['v'; 8],
box_1: Box::new("some_other_string".to_owned()),
wrapping_1: Wrapping(0u32),
};
assert_eq!(restored_state, expected_state);
snapshot_blob = v2_hardcoded_snapshot;
restored_state = <TestStruct as Versionize>::deserialize(&mut snapshot_blob, &vm, 2).unwrap();
expected_state = TestStruct {
usize_1: 1,
isize_1: 2,
u16_1: 4,
u64_1: 0xABCDu64,
i8_1: -1,
i16_1: 0,
i32_1: 32,
i64_1: 0xFFFFi64,
f32_1: 0.5,
f64_1: 64.5,
char_1: 'a',
bool_1: true,
string_1: "some_string".to_owned(),
enum_1: TestState::Two(14),
option_1: Some(129),
vec_1: vec!['v'; 8],
box_1: Box::new("some_other_string".to_owned()),
wrapping_1: Wrapping(0u32),
};
assert_eq!(restored_state, expected_state);
snapshot_blob = v3_hardcoded_snapshot;
restored_state = <TestStruct as Versionize>::deserialize(&mut snapshot_blob, &vm, 3).unwrap();
expected_state = TestStruct {
usize_1: 1,
isize_1: 2,
u16_1: 4,
u64_1: 0x0Du64,
i8_1: -1,
i16_1: 0,
i32_1: 32,
i64_1: 0x0Ei64,
f32_1: 0.5,
f64_1: 64.5,
char_1: 'a',
bool_1: true,
string_1: "some_string".to_owned(),
enum_1: TestState::Two(14),
option_1: Some(129),
vec_1: vec!['a'; 4],
box_1: Box::new("some_other_string".to_owned()),
wrapping_1: Wrapping(255u32),
};
assert_eq!(restored_state, expected_state);
snapshot_blob = v4_hardcoded_snapshot;
restored_state = <TestStruct as Versionize>::deserialize(&mut snapshot_blob, &vm, 4).unwrap();
expected_state = TestStruct {
usize_1: 1,
isize_1: 12,
u16_1: 4,
u64_1: 0x0Du64,
i8_1: -1,
i16_1: 0,
i32_1: 32,
i64_1: 0x0Ei64,
f32_1: 0.5,
f64_1: 64.5,
char_1: 'a',
bool_1: true,
string_1: "some_string".to_owned(),
enum_1: TestState::Two(14),
option_1: Some(129),
vec_1: vec!['v'; 8],
box_1: Box::new("some_other_string".to_owned()),
wrapping_1: Wrapping(255u32),
};
assert_eq!(restored_state, expected_state);
}
#[test]
fn test_hardcoded_enum_deserialization() {
#[rustfmt::skip]
let v1_hardcoded_snapshot: &[u8] = &[
0x00, 0x00, 0x00, 0x00,
];
#[rustfmt::skip]
let v2_hardcoded_snapshot: &[u8] = &[
0x00, 0x00, 0x00, 0x00,
];
#[rustfmt::skip]
let unexpected_v1_hardcoded_snapshot: &[u8] = &[
0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
#[rustfmt::skip]
let invalid_v1_hardcoded_snapshot: &[u8] = &[
0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
let mut vm = VersionMap::new();
vm.new_version().set_type_version(TestState::type_id(), 2);
let mut snapshot_blob = v1_hardcoded_snapshot;
let mut restored_state =
<TestState as Versionize>::deserialize(&mut snapshot_blob, &vm, 1).unwrap();
assert_eq!(restored_state, TestState::Zero);
snapshot_blob = v2_hardcoded_snapshot;
restored_state = <TestState as Versionize>::deserialize(&mut snapshot_blob, &vm, 2).unwrap();
assert_eq!(restored_state, TestState::Zero);
snapshot_blob = unexpected_v1_hardcoded_snapshot;
restored_state = <TestState as Versionize>::deserialize(&mut snapshot_blob, &vm, 1).unwrap();
assert_eq!(restored_state, TestState::Two(5));
snapshot_blob = invalid_v1_hardcoded_snapshot;
assert_eq!(
<TestState as Versionize>::deserialize(&mut snapshot_blob, &vm, 1).unwrap_err(),
VersionizeError::Deserialize("Unknown variant_index 3".to_owned())
);
}
#[derive(Debug, PartialEq, Eq, Versionize)]
pub struct A {
a: u32,
#[version(start = 1, end = 2)]
b: Option<TestState>,
#[version(start = 2, default_fn = "default_c")]
c: String,
}
#[derive(Debug, PartialEq, Eq, Versionize)]
pub struct X {
x: bool,
a_1: A,
#[version(end = 3, default_fn = "default_y")]
y: Box<usize>,
#[version(start = 3, default_fn = "default_z")]
z: Vec<u8>,
}
impl A {
fn default_c(_source_version: u16) -> String {
"some_string".to_owned()
}
}
impl X {
fn default_y(_source_version: u16) -> Box<usize> {
Box::from(4)
}
fn default_z(_source_version: u16) -> Vec<u8> {
vec![16, 4]
}
}
#[test]
fn test_nested_structs_deserialization() {
#[rustfmt::skip]
let v1_hardcoded_snapshot: &[u8] = &[
0x00, 0x10, 0x00, 0x00, 0x00,
0x01, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
#[rustfmt::skip]
let v2_hardcoded_snapshot: &[u8] = &[
0x00, 0x10, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x72, 0x61, 0x6E, 0x64, 0x6F, 0x6D,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
#[rustfmt::skip]
let v3_hardcoded_snapshot: &[u8] = &[
0x00, 0x10, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x72, 0x61, 0x6E, 0x64, 0x6F, 0x6D,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
];
let mut vm = VersionMap::new();
vm.new_version()
.set_type_version(A::type_id(), 2)
.set_type_version(X::type_id(), 2)
.set_type_version(TestState::type_id(), 2)
.new_version()
.set_type_version(X::type_id(), 3);
let mut snapshot_blob = v1_hardcoded_snapshot;
let mut restored_state = <X as Versionize>::deserialize(&mut snapshot_blob, &vm, 1).unwrap();
let mut expected_state = X {
x: false,
a_1: A {
a: 16u32,
b: Some(TestState::One(4)),
c: "some_string".to_owned(),
},
y: Box::from(2),
z: vec![16, 4],
};
assert_eq!(restored_state, expected_state);
snapshot_blob = v2_hardcoded_snapshot;
restored_state = <X as Versionize>::deserialize(&mut snapshot_blob, &vm, 2).unwrap();
expected_state = X {
x: false,
a_1: A {
a: 16u32,
b: None,
c: "random".to_owned(),
},
y: Box::from(2),
z: vec![16, 4],
};
assert_eq!(restored_state, expected_state);
snapshot_blob = v3_hardcoded_snapshot;
restored_state = <X as Versionize>::deserialize(&mut snapshot_blob, &vm, 3).unwrap();
expected_state = X {
x: false,
a_1: A {
a: 16u32,
b: None,
c: "random".to_owned(),
},
y: Box::from(4),
z: vec![24; 4],
};
assert_eq!(restored_state, expected_state);
}
pub const SIZE: usize = 10;
pub mod dummy_mod {
pub const SIZE: usize = 20;
}
#[test]
fn test_versionize_struct_with_array() {
#[derive(Debug, PartialEq, Versionize)]
struct TestStruct {
a: [u32; SIZE],
b: [u8; dummy_mod::SIZE],
c: Option<[i16; SIZE]>,
}
let test_struct = TestStruct {
a: [1; SIZE],
b: [2; dummy_mod::SIZE],
c: Some([3; SIZE]),
};
let mut mem = vec![0; 4096];
let version_map = VersionMap::new();
test_struct
.serialize(&mut mem.as_mut_slice(), &version_map, 1)
.unwrap();
let restored_test_struct =
TestStruct::deserialize(&mut mem.as_slice(), &version_map, 1).unwrap();
assert_eq!(restored_test_struct, test_struct);
}
#[derive(Clone, Debug, PartialEq, Eq, Versionize)]
pub enum DeviceStatus {
Inactive,
Active,
#[version(start = 2, default_fn = "default_is_activating")]
IsActivating(u32),
}
impl Default for DeviceStatus {
fn default() -> Self {
Self::Inactive
}
}
#[derive(Clone, Debug, PartialEq, Eq, Versionize)]
pub enum OperationSupported {
Add,
Remove,
RemoveAndAdd(bool),
#[version(start = 2, default_fn = "default_update")]
Update(String),
}
impl Default for OperationSupported {
fn default() -> Self {
Self::Add
}
}
impl DeviceStatus {
fn default_is_activating(&self, target_version: u16) -> VersionizeResult<DeviceStatus> {
match target_version {
1 => Ok(DeviceStatus::Inactive),
i => Err(VersionizeError::Serialize(format!(
"Unknown target version: {}",
i
))),
}
}
}
impl OperationSupported {
fn default_update(&self, target_version: u16) -> VersionizeResult<OperationSupported> {
match target_version {
1 => Ok(OperationSupported::RemoveAndAdd(true)),
i => Err(VersionizeError::Serialize(format!(
"Unknown target version: {}",
i
))),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Versionize)]
pub struct Device {
name: String,
id: Wrapping<u32>,
#[version(start = 2, ser_fn = "ser_is_activated")]
is_activated: bool,
some_params: Vec<String>,
#[version(
start = 2,
default_fn = "default_ops",
ser_fn = "ser_ops",
de_fn = "de_ops"
)]
operations: Vec<OperationSupported>,
status: DeviceStatus,
#[version(
start = 2,
default_fn = "default_queues_limit",
ser_fn = "ser_queues_limit"
)]
no_queues_limit: usize,
queues: Vec<u8>,
features: u32,
#[version(start = 3, ser_fn = "ser_extra", de_fn = "de_extra")]
extra_features: u64,
}
impl Device {
fn default_ops(_target_version: u16) -> Vec<OperationSupported> {
vec![OperationSupported::Add, OperationSupported::Remove]
}
fn default_queues_limit(_target_version: u16) -> usize {
2
}
fn ser_ops(&mut self, target_version: u16) -> VersionizeResult<()> {
assert!(target_version < 2);
self.features |= 1;
Ok(())
}
fn de_ops(&mut self, target_version: u16) -> VersionizeResult<()> {
assert!(target_version < 2);
if self.some_params.contains(&"active".to_owned()) {
self.status = DeviceStatus::Active;
}
Ok(())
}
fn ser_queues_limit(&mut self, target_version: u16) -> VersionizeResult<()> {
assert!(target_version < 2);
if self.queues.len() > 2 {
return Err(VersionizeError::Semantic("Too many queues.".to_owned()));
}
Ok(())
}
fn ser_is_activated(&mut self, target_version: u16) -> VersionizeResult<()> {
assert!(target_version < 2);
self.some_params.push("active".to_owned());
self.some_params.retain(|x| x.clone() != *"inactive");
Ok(())
}
fn ser_extra(&mut self, target_version: u16) -> VersionizeResult<()> {
assert!(target_version < 3);
self.some_params.push("extra_features".to_owned());
Ok(())
}
fn de_extra(&mut self, target_version: u16) -> VersionizeResult<()> {
assert!(target_version < 3);
if self.queues.len() > self.no_queues_limit {
return Err(VersionizeError::Semantic("Too many queues.".to_owned()));
}
self.features |= 1u32 << 31;
Ok(())
}
}
#[test]
fn test_versionize_struct_with_enums() {
let mut vm = VersionMap::new();
vm.new_version()
.set_type_version(Device::type_id(), 2)
.set_type_version(DeviceStatus::type_id(), 2)
.new_version()
.set_type_version(Device::type_id(), 3)
.set_type_version(OperationSupported::type_id(), 2);
let mut state = Device {
name: "block".to_owned(),
id: Wrapping(1u32),
is_activated: true,
some_params: vec!["inactive".to_owned()],
operations: vec![
OperationSupported::Add,
OperationSupported::Update("random".to_owned()),
],
status: DeviceStatus::Inactive,
no_queues_limit: 3,
queues: vec![1u8, 2u8],
features: 6u32,
extra_features: 0u64,
};
let mut snapshot_mem = vec![0u8; 1024];
state
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 1)
.unwrap();
let mut restored_state =
<Device as Versionize>::deserialize(&mut snapshot_mem.as_slice(), &vm, 1).unwrap();
let mut expected_state = Device {
name: "block".to_owned(),
id: Wrapping(1u32),
is_activated: false,
some_params: vec!["active".to_owned(), "extra_features".to_owned()],
operations: vec![OperationSupported::Add, OperationSupported::Remove],
status: DeviceStatus::Active,
no_queues_limit: 2,
queues: vec![1u8, 2u8],
features: 0x8000_0007u32,
extra_features: 0u64,
};
assert_eq!(expected_state, restored_state);
state
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 2)
.unwrap();
restored_state =
<Device as Versionize>::deserialize(&mut snapshot_mem.as_slice(), &vm, 2).unwrap();
expected_state = Device {
name: "block".to_owned(),
id: Wrapping(1u32),
is_activated: true,
some_params: vec!["inactive".to_owned(), "extra_features".to_owned()],
operations: vec![
OperationSupported::Add,
OperationSupported::RemoveAndAdd(true),
],
status: DeviceStatus::Inactive,
no_queues_limit: 3,
queues: vec![1u8, 2u8],
features: 0x8000_0006u32,
extra_features: 0u64,
};
assert_eq!(expected_state, restored_state);
state
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 3)
.unwrap();
restored_state =
<Device as Versionize>::deserialize(&mut snapshot_mem.as_slice(), &vm, 3).unwrap();
expected_state = Device {
name: "block".to_owned(),
id: Wrapping(1u32),
is_activated: true,
some_params: vec!["inactive".to_owned()],
operations: vec![
OperationSupported::Add,
OperationSupported::Update("random".to_owned()),
],
status: DeviceStatus::Inactive,
no_queues_limit: 3,
queues: vec![1u8, 2u8],
features: 6u32,
extra_features: 0u64,
};
assert_eq!(expected_state, restored_state);
state.queues = vec![1u8, 2u8, 3u8, 4u8];
assert_eq!(
state
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 1)
.unwrap_err(),
VersionizeError::Semantic("Too many queues.".to_owned())
);
state
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 2)
.unwrap();
assert_eq!(
<Device as Versionize>::deserialize(&mut snapshot_mem.as_slice(), &vm, 2).unwrap_err(),
VersionizeError::Semantic("Too many queues.".to_owned())
);
}
#[derive(Clone, Debug, PartialEq, Eq, Versionize)]
pub enum State {
Zero,
One(bool),
#[version(start = 2, default_fn = "default_state_two")]
Two(Vec<u8>),
#[version(start = 2, default_fn = "default_state_three")]
Three(String),
#[version(start = 3, default_fn = "default_state_four")]
Four(Option<u64>),
}
impl Default for State {
fn default() -> Self {
Self::One(false)
}
}
impl State {
fn default_state_two(&self, target_version: u16) -> VersionizeResult<State> {
match target_version {
1 => Ok(State::One(true)),
i => Err(VersionizeError::Serialize(format!(
"Unknown target version: {}",
i
))),
}
}
fn default_state_three(&self, target_version: u16) -> VersionizeResult<State> {
match target_version {
1 => Ok(State::One(false)),
i => Err(VersionizeError::Serialize(format!(
"Unknown target version: {}",
i
))),
}
}
fn default_state_four(&self, target_version: u16) -> VersionizeResult<State> {
match target_version {
2 => Ok(State::Three("abc".to_owned())),
1 => Ok(State::Zero),
i => Err(VersionizeError::Serialize(format!(
"Unknown target version: {}",
i
))),
}
}
}
#[test]
fn test_versionize_enum() {
let mut vm = VersionMap::new();
vm.new_version()
.set_type_version(State::type_id(), 2)
.new_version()
.set_type_version(State::type_id(), 3);
let mut snapshot_mem = vec![0u8; 1024];
let mut state = State::One(true);
state
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 1)
.unwrap();
let mut restored_state =
<State as Versionize>::deserialize(&mut snapshot_mem.as_slice(), &vm, 1).unwrap();
assert_eq!(state, restored_state);
state = State::Four(Some(0x1234_5678_8765_4321u64));
state
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 1)
.unwrap();
restored_state =
<State as Versionize>::deserialize(&mut snapshot_mem.as_slice(), &vm, 1).unwrap();
assert_eq!(restored_state, State::Zero);
state
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 2)
.unwrap();
restored_state =
<State as Versionize>::deserialize(&mut snapshot_mem.as_slice(), &vm, 2).unwrap();
assert_eq!(restored_state, State::Three("abc".to_owned()));
state = State::Three("some_string".to_owned());
state
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 1)
.unwrap();
restored_state =
<State as Versionize>::deserialize(&mut snapshot_mem.as_slice(), &vm, 2).unwrap();
assert_eq!(restored_state, State::One(false));
}
#[derive(Clone, Debug, PartialEq, Versionize)]
pub struct S {
a: f64,
b: i64,
}
#[derive(Clone, Debug, PartialEq, Versionize)]
pub struct Test {
usize_1: usize,
#[version(start = 2, end = 3, ser_fn = "ser_isize", de_fn = "de_isize")]
isize_1: isize,
#[version(start = 2)]
u8_1: u8,
#[version(end = 4, default_fn = "default_vec")]
vec_1: Vec<u16>,
#[version(start = 3)]
wrapping_1: Wrapping<u32>,
#[version(
end = 3,
default_fn = "default_u64",
ser_fn = "ser_u64",
de_fn = "de_u64"
)]
u64_1: u64,
#[version(start = 2, ser_fn = "ser_bool")]
bool_1: bool,
enum_1: State,
i8_1: i8,
i16_1: i16,
#[version(start = 3, end = 4)]
i32_1: i32,
#[version(start = 2, default_fn = "default_box", de_fn = "de_box")]
box_1: Box<S>,
#[version(start = 2, end = 3, default_fn = "default_f32")]
f32_1: f32,
char_1: char,
#[version(
end = 3,
default_fn = "default_option",
ser_fn = "ser_option",
de_fn = "de_option"
)]
option_1: Option<String>,
}
impl Test {
fn default_vec(_target_version: u16) -> Vec<u16> {
vec![0x0102u16; 4]
}
fn default_u64(_target_version: u16) -> u64 {
0x0102_0102_0102_0102u64
}
fn default_f32(_target_version: u16) -> f32 {
0.5
}
fn default_box(_target_version: u16) -> Box<S> {
Box::new(S { a: 1.5, b: 2 })
}
fn default_option(_target_version: u16) -> Option<String> {
Some("something".to_owned())
}
fn ser_isize(&mut self, target_version: u16) -> VersionizeResult<()> {
assert_ne!(target_version, 2);
self.vec_1.push(0x0304u16);
if self.i8_1 == -1 {
return Err(VersionizeError::Semantic(
"Unexpected value for `i8` field.".to_owned(),
));
}
Ok(())
}
fn ser_u64(&mut self, target_version: u16) -> VersionizeResult<()> {
assert!(target_version >= 3);
self.vec_1.pop();
if self.u8_1 == 4 {
self.bool_1 = false;
}
Ok(())
}
fn ser_bool(&mut self, target_version: u16) -> VersionizeResult<()> {
assert!(target_version < 2);
self.vec_1.push(0x0506u16);
self.vec_1.push(0x0708u16);
Ok(())
}
fn ser_option(&mut self, target_version: u16) -> VersionizeResult<()> {
assert!(target_version >= 3);
self.u8_1 += 2;
if self.vec_1.len() == 10 {
return Err(VersionizeError::Semantic("Vec is full.".to_owned()));
}
Ok(())
}
fn de_isize(&mut self, target_version: u16) -> VersionizeResult<()> {
assert_ne!(target_version, 2);
self.u8_1 += 3;
Ok(())
}
fn de_u64(&mut self, target_version: u16) -> VersionizeResult<()> {
assert!(target_version >= 3);
self.vec_1.push(0x0101u16);
Ok(())
}
fn de_box(&mut self, target_version: u16) -> VersionizeResult<()> {
assert!(target_version < 2);
self.option_1 = Some("box_change".to_owned());
if self.vec_1.len() == 3 {
return Err(VersionizeError::Semantic(
"Vec len is too small.".to_owned(),
));
}
Ok(())
}
fn de_option(&mut self, target_version: u16) -> VersionizeResult<()> {
assert!(target_version >= 3);
self.enum_1 = State::Two(vec![1; 4]);
Ok(())
}
}
#[test]
fn test_versionize_struct() {
let mut vm = VersionMap::new();
vm.new_version()
.set_type_version(Test::type_id(), 2)
.set_type_version(State::type_id(), 2)
.new_version()
.set_type_version(Test::type_id(), 3)
.set_type_version(State::type_id(), 3);
let mut state = Test {
usize_1: 0x0102_0304_0506_0708usize,
isize_1: -0x1122_3344_5566_7788isize,
u8_1: 4,
vec_1: vec![0x1122u16; 5],
wrapping_1: Wrapping(4u32),
u64_1: 0x0102_0304_0506_0708u64,
bool_1: false,
enum_1: State::Four(Some(0x0102_0304_0506_0708u64)),
i8_1: 8,
i16_1: -12,
i32_1: -0x1234_5678,
box_1: Box::new(S { a: 4.5, b: 4 }),
f32_1: 1.25,
char_1: 'c',
option_1: None,
};
let mut snapshot_mem = vec![0u8; 1024];
state
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 1)
.unwrap();
let mut restored_state =
<Test as Versionize>::deserialize(&mut snapshot_mem.as_slice(), &vm, 1).unwrap();
let mut expected_state = Test {
usize_1: 0x0102_0304_0506_0708usize,
isize_1: 0isize,
u8_1: 3,
vec_1: vec![
0x1122u16, 0x1122u16, 0x1122u16, 0x1122u16, 0x1122u16, 0x0304u16, 0x0506u16, 0x0708u16,
],
wrapping_1: Wrapping(0u32),
u64_1: 0x0102_0304_0506_0708u64,
bool_1: false,
enum_1: State::Zero,
i8_1: 8,
i16_1: -12,
i32_1: 0,
box_1: Box::new(S { a: 1.5, b: 2 }),
f32_1: 0.5,
char_1: 'c',
option_1: Some("box_change".to_owned()),
};
assert_eq!(expected_state, restored_state);
state
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 2)
.unwrap();
restored_state =
<Test as Versionize>::deserialize(&mut snapshot_mem.as_slice(), &vm, 2).unwrap();
expected_state = Test {
usize_1: 0x0102_0304_0506_0708usize,
isize_1: -0x1122_3344_5566_7788isize,
u8_1: 4,
vec_1: vec![0x1122u16, 0x1122u16, 0x1122u16, 0x1122u16, 0x1122u16],
wrapping_1: Wrapping(0u32),
u64_1: 0x0102_0304_0506_0708u64,
bool_1: false,
enum_1: State::Three("abc".to_owned()),
i8_1: 8,
i16_1: -12,
i32_1: 0,
box_1: Box::new(S { a: 4.5, b: 4 }),
f32_1: 1.25,
char_1: 'c',
option_1: None,
};
assert_eq!(expected_state, restored_state);
state
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 3)
.unwrap();
restored_state =
<Test as Versionize>::deserialize(&mut snapshot_mem.as_slice(), &vm, 3).unwrap();
expected_state = Test {
usize_1: 0x0102_0304_0506_0708usize,
isize_1: 0isize,
u8_1: 9,
vec_1: vec![
0x1122u16, 0x1122u16, 0x1122u16, 0x1122u16, 0x1122u16, 0x0101u16,
],
wrapping_1: Wrapping(4u32),
u64_1: 0x0102_0102_0102_0102u64,
bool_1: false,
enum_1: State::Two(vec![1; 4]),
i8_1: 8,
i16_1: -12,
i32_1: -0x1234_5678,
box_1: Box::new(S { a: 4.5, b: 4 }),
f32_1: 0.5,
char_1: 'c',
option_1: Some("something".to_owned()),
};
assert_eq!(expected_state, restored_state);
state.vec_1 = Vec::new();
state
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 1)
.unwrap();
assert_eq!(
<Test as Versionize>::deserialize(&mut snapshot_mem.as_slice(), &vm, 1).unwrap_err(),
VersionizeError::Semantic("Vec len is too small.".to_owned())
);
state.vec_1 = vec![0x1122u16; 10];
assert_eq!(
state
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 3)
.unwrap_err(),
VersionizeError::Semantic("Vec is full.".to_owned())
);
state.i8_1 = -1;
assert_eq!(
state
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 1)
.unwrap_err(),
VersionizeError::Semantic("Unexpected value for `i8` field.".to_owned())
);
state.i8_1 = 0;
snapshot_mem = vec![0u8; 8];
assert_eq!(
state
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 1)
.unwrap_err(),
VersionizeError::Serialize(
"Io(Error { kind: WriteZero, message: \"failed to write whole buffer\" })".to_owned()
)
);
snapshot_mem = vec![0u8; 256];
state
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 1)
.unwrap();
snapshot_mem.truncate(10);
assert_eq!(
<Test as Versionize>::deserialize(&mut snapshot_mem.as_slice(), &vm, 1).unwrap_err(),
VersionizeError::Deserialize(
"Io(Error { kind: UnexpectedEof, message: \"failed to fill whole buffer\" })"
.to_owned()
)
);
}
#[repr(C)]
#[derive(Debug, Default, Versionize)]
struct Message {
pub len: u32,
#[version(end = 4)]
pub padding: u32,
pub value: u32,
#[version(start = 2, default_fn = "default_extra_value")]
pub extra_value: u16,
#[version(start = 3, end = 4, default_fn = "default_status")]
pub status: Wrapping<bool>,
pub entries: __IncompleteArrayField<u32>,
}
impl Message {
fn default_extra_value(_source_version: u16) -> u16 {
4
}
fn default_status(_source_version: u16) -> Wrapping<bool> {
Wrapping(false)
}
}
#[repr(C)]
#[derive(Debug, Default, Versionize)]
struct Message2 {
pub len: u32,
#[version(end = 4)]
pub padding: u32,
pub value: u32,
#[version(start = 2, default_fn = "default_extra_value")]
pub extra_value: u16,
#[version(start = 3, end = 4, default_fn = "default_status")]
pub status: Wrapping<bool>,
pub entries: __IncompleteArrayField<u32>,
}
impl Message2 {
fn default_extra_value(_source_version: u16) -> u16 {
4
}
fn default_status(_source_version: u16) -> Wrapping<bool> {
Wrapping(false)
}
}
generate_fam_struct_impl!(Message, u32, entries, u32, len, 100);
generate_fam_struct_impl!(Message2, u32, entries, u32, len, 1);
#[repr(C)]
#[derive(Default)]
pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>, [T; 0]);
impl<T> __IncompleteArrayField<T> {
#[inline]
pub fn new() -> Self {
__IncompleteArrayField(::std::marker::PhantomData, [])
}
#[inline]
pub unsafe fn as_ptr(&self) -> *const T {
self as *const __IncompleteArrayField<T> as *const T
}
#[inline]
pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
self as *mut __IncompleteArrayField<T> as *mut T
}
#[inline]
pub unsafe fn as_slice(&self, len: usize) -> &[T] {
::std::slice::from_raw_parts(self.as_ptr(), len)
}
#[inline]
pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] {
::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
}
}
impl<T> Debug for __IncompleteArrayField<T> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
fmt.write_str("__IncompleteArrayField")
}
}
impl<T> ::std::clone::Clone for __IncompleteArrayField<T> {
#[inline]
fn clone(&self) -> Self {
Self::new()
}
}
impl<T> Versionize for __IncompleteArrayField<T> {
#[inline]
fn serialize<W: std::io::Write>(
&self,
_writer: &mut W,
_version_map: &VersionMap,
_app_version: u16,
) -> VersionizeResult<()> {
Ok(())
}
#[inline]
fn deserialize<R: std::io::Read>(
_reader: &mut R,
_version_map: &VersionMap,
_app_version: u16,
) -> VersionizeResult<Self> {
Ok(Self::new())
}
fn version() -> u16 {
1
}
}
type MessageFamStructWrapper = FamStructWrapper<Message>;
type Message2FamStructWrapper = FamStructWrapper<Message2>;
#[test]
fn test_versionize_famstructwrapper() {
let mut vm = VersionMap::new();
vm.new_version()
.set_type_version(Message::type_id(), 2)
.new_version()
.set_type_version(Message::type_id(), 3)
.new_version()
.set_type_version(Message::type_id(), 4);
let mut state = MessageFamStructWrapper::new(0).unwrap();
state.as_mut_fam_struct().padding = 8;
state.as_mut_fam_struct().extra_value = 16;
state.as_mut_fam_struct().status = Wrapping(true);
state.push(1).unwrap();
state.push(2).unwrap();
let mut snapshot_mem = vec![0u8; 256];
state
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 1)
.unwrap();
let mut restored_state =
<MessageFamStructWrapper as Versionize>::deserialize(&mut snapshot_mem.as_slice(), &vm, 1)
.unwrap();
let mut original_values = state.as_slice();
let mut restored_values = restored_state.as_slice();
assert_eq!(original_values, restored_values);
assert_eq!(
restored_values.len(),
state.as_fam_struct_ref().len as usize
);
assert_eq!(
state.as_fam_struct_ref().padding,
restored_state.as_fam_struct_ref().padding
);
assert_eq!(4, restored_state.as_fam_struct_ref().extra_value);
assert_eq!(Wrapping(false), restored_state.as_fam_struct_ref().status);
state
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 2)
.unwrap();
restored_state =
<MessageFamStructWrapper as Versionize>::deserialize(&mut snapshot_mem.as_slice(), &vm, 2)
.unwrap();
original_values = state.as_slice();
restored_values = restored_state.as_slice();
assert_eq!(original_values, restored_values);
assert_eq!(
state.as_fam_struct_ref().padding,
restored_state.as_fam_struct_ref().padding
);
assert_eq!(
state.as_fam_struct_ref().extra_value,
restored_state.as_fam_struct_ref().extra_value
);
assert_eq!(Wrapping(false), restored_state.as_fam_struct_ref().status);
state
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 3)
.unwrap();
restored_state =
<MessageFamStructWrapper as Versionize>::deserialize(&mut snapshot_mem.as_slice(), &vm, 3)
.unwrap();
assert_eq!(
state.as_fam_struct_ref().padding,
restored_state.as_fam_struct_ref().padding
);
assert_eq!(
state.as_fam_struct_ref().extra_value,
restored_state.as_fam_struct_ref().extra_value
);
assert_eq!(Wrapping(true), restored_state.as_fam_struct_ref().status);
state
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 4)
.unwrap();
restored_state =
<MessageFamStructWrapper as Versionize>::deserialize(&mut snapshot_mem.as_slice(), &vm, 4)
.unwrap();
assert_eq!(0, restored_state.as_fam_struct_ref().padding);
assert_eq!(
state.as_fam_struct_ref().extra_value,
restored_state.as_fam_struct_ref().extra_value
);
assert_eq!(Wrapping(false), restored_state.as_fam_struct_ref().status);
snapshot_mem = vec![0u8; 16];
assert_eq!(
state
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 1)
.unwrap_err(),
VersionizeError::Serialize(
"Io(Error { kind: WriteZero, message: \"failed to write whole buffer\" })".to_owned()
)
);
}
#[derive(Versionize)]
pub struct FamStructTest {
some_u8: u8,
message_box: Box<MessageFamStructWrapper>,
#[version(start = 2, default_fn = "default_option", de_fn = "de_option")]
some_option: Option<S>,
#[version(start = 3)]
some_string: String,
#[version(end = 3, default_fn = "default_message", de_fn = "de_message")]
messages: Vec<MessageFamStructWrapper>,
}
impl FamStructTest {
fn default_message(_target_version: u16) -> Vec<MessageFamStructWrapper> {
let mut f = MessageFamStructWrapper::new(0).unwrap();
f.as_mut_fam_struct().padding = 1;
f.as_mut_fam_struct().extra_value = 2;
f.push(10).unwrap();
f.push(20).unwrap();
vec![f]
}
fn default_option(_target_version: u16) -> Option<S> {
Some(S { a: 0.5, b: 0 })
}
fn de_message(&mut self, target_version: u16) -> VersionizeResult<()> {
assert_ne!(target_version, 2);
self.some_option = None;
self.some_string = "some_new_string".to_owned();
Ok(())
}
fn de_option(&mut self, target_version: u16) -> VersionizeResult<()> {
assert!(target_version < 2);
let mut f = MessageFamStructWrapper::new(0).unwrap();
f.as_mut_fam_struct().padding = 3;
f.as_mut_fam_struct().extra_value = 4;
f.push(10).unwrap();
f.push(20).unwrap();
self.messages.push(f);
Ok(())
}
}
#[test]
fn test_versionize_struct_with_famstructs() {
let mut vm = VersionMap::new();
vm.new_version()
.set_type_version(FamStructTest::type_id(), 2)
.set_type_version(Message::type_id(), 2)
.new_version()
.set_type_version(FamStructTest::type_id(), 3)
.set_type_version(Message::type_id(), 3);
let mut snapshot_mem = vec![0u8; 1024];
let mut f = MessageFamStructWrapper::new(0).unwrap();
f.as_mut_fam_struct().padding = 5;
f.as_mut_fam_struct().extra_value = 6;
f.push(10).unwrap();
let mut f2 = MessageFamStructWrapper::new(0).unwrap();
f2.as_mut_fam_struct().padding = 7;
f2.as_mut_fam_struct().extra_value = 8;
f2.push(20).unwrap();
let state = FamStructTest {
some_u8: 1,
messages: vec![f],
some_string: "some_string".to_owned(),
message_box: Box::new(f2),
some_option: None,
};
state
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 1)
.unwrap();
let mut restored_state =
<FamStructTest as Versionize>::deserialize(&mut snapshot_mem.as_slice(), &vm, 1).unwrap();
assert_eq!(restored_state.some_string, String::default());
assert_eq!(restored_state.some_option, Some(S { a: 0.5, b: 0 }));
let messages = restored_state.messages;
assert_eq!(messages.len(), 2);
for message in messages.iter() {
assert_eq!(message.as_fam_struct_ref().extra_value, 4);
assert_eq!(message.as_fam_struct_ref().status, Wrapping(false));
}
assert_eq!(messages[0].as_fam_struct_ref().padding, 5);
assert_eq!(messages[1].as_fam_struct_ref().padding, 3);
state
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 2)
.unwrap();
restored_state =
<FamStructTest as Versionize>::deserialize(&mut snapshot_mem.as_slice(), &vm, 2).unwrap();
assert_eq!(restored_state.some_string, String::default());
assert_eq!(restored_state.some_option, None);
let messages = restored_state.messages;
assert_eq!(messages.len(), 1);
state
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 3)
.unwrap();
restored_state =
<FamStructTest as Versionize>::deserialize(&mut snapshot_mem.as_slice(), &vm, 3).unwrap();
assert_eq!(restored_state.some_string, "some_new_string".to_owned());
assert_eq!(restored_state.some_option, None);
let messages = restored_state.messages;
assert_eq!(messages.len(), 1);
assert_eq!(messages[0].as_fam_struct_ref().padding, 1);
}
#[derive(Clone, Versionize)]
pub struct SomeStruct {
message: MessageFamStructWrapper,
#[version(start = 2, ser_fn = "ser_u16")]
some_u16: u16,
}
impl SomeStruct {
fn ser_u16(&mut self, target_version: u16) -> VersionizeResult<()> {
assert!(target_version < 2);
self.message.as_mut_fam_struct().padding += 2;
Ok(())
}
}
#[derive(Clone, Versionize)]
pub struct SomeStruct2 {
message: Message2FamStructWrapper,
#[version(start = 2, ser_fn = "ser_u16")]
some_u16: u16,
}
impl SomeStruct2 {
fn ser_u16(&mut self, target_version: u16) -> VersionizeResult<()> {
assert!(target_version < 2);
self.message.as_mut_fam_struct().padding += 2;
Ok(())
}
}
#[test]
fn test_famstructwrapper_clone() {
let mut vm = VersionMap::new();
vm.new_version().set_type_version(SomeStruct::type_id(), 2);
let mut f = MessageFamStructWrapper::new(0).unwrap();
f.as_mut_fam_struct().padding = 8;
f.push(1).unwrap();
f.push(2).unwrap();
let state = SomeStruct {
message: f,
some_u16: 2,
};
let mut snapshot_mem = vec![0u8; 128];
state
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 1)
.unwrap();
let mut restored_state =
<SomeStruct as Versionize>::deserialize(&mut snapshot_mem.as_slice(), &vm, 1).unwrap();
assert!(
<SomeStruct2 as Versionize>::deserialize(&mut snapshot_mem.as_slice(), &vm, 1).is_err()
);
let original_values = state.message.as_slice();
let restored_values = restored_state.message.as_slice();
assert_ne!(
state.message.as_fam_struct_ref().padding,
restored_state.message.as_fam_struct_ref().padding
);
assert_eq!(original_values, restored_values);
assert_eq!(10, restored_state.message.as_fam_struct_ref().padding);
state
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 2)
.unwrap();
restored_state =
<SomeStruct as Versionize>::deserialize(&mut snapshot_mem.as_slice(), &vm, 2).unwrap();
assert_eq!(
state.message.as_fam_struct_ref().padding,
restored_state.message.as_fam_struct_ref().padding
);
assert_eq!(8, restored_state.message.as_fam_struct_ref().padding);
}