test: refactor test

This commit is contained in:
Vincent Herlemont
2023-10-29 09:44:24 +01:00
parent 816d65078c
commit f806be1706
17 changed files with 138 additions and 481 deletions

View File

@@ -31,7 +31,7 @@ criterion = { version = "0.5.1" }
skeptic = "0.13"
[features]
default = ["serde", "bincode_1_3", "bincode_2_rc", "postcard_1_0"]
default = ["serde", "bincode_1_3"]
[[bench]]
name = "overhead"

54
justfile Normal file
View File

@@ -0,0 +1,54 @@
set shell := ["nu", "-c"]
default:
@just --list --unsorted;
build_no_default:
cargo build --no-default-features
build_default:
cargo build
build_serde:
cargo build --no-default-features --features serde
build_bincode_1_3:
cargo build --features bincode_1_3
build_no_default_bincode_1_3:
cargo build --no-default-features --features serde --features bincode_1_3
build_bincode_2_rc:
cargo build --features bincode_2_rc
build_no_default_bincode_2_rc:
cargo build --no-default-features --features serde --features bincode_2_rc
build_postcard_1_0:
cargo build --features postcard_1_0
build_no_default_postcard_1_0:
cargo build --no-default-features --features serde --features postcard_1_0
build_all: build_no_default build_default build_serde build_bincode_1_3 build_no_default_bincode_1_3 build_bincode_2_rc build_no_default_bincode_2_rc build_postcard_1_0 build_no_default_postcard_1_0
_tests_crate args='':
cd tests_crate; \
cargo test {{args}}
test_no_default:
@just _tests_crate '--no-default-features'
test_default:
@just _tests_crate args=''
test_bincode_1_3:
@just _tests_crate '--features bincode_1_3'
test_bincode_2_rc:
@just _tests_crate '--features bincode_2_rc'
test_postcard_1_0:
@just _tests_crate '--features postcard_1_0'
test_all: test_no_default test_default test_bincode_1_3 test_bincode_2_rc test_postcard_1_0

View File

@@ -1,5 +1,8 @@
#[cfg(all(feature = "serde", feature = "bincode_1_3"))]
pub mod bincode_1_3;
#[cfg(all(feature = "serde", feature = "bincode_2_rc"))]
pub mod bincode_2_rc;
#[cfg(all(feature = "serde", feature = "postcard_1_0"))]
pub mod postcard_1_0;
/// Encode trait for your own encoding method.

View File

@@ -15,13 +15,26 @@
//!
//! See examples in the [README.md](https://github.com/vincent-herlemont/native_model) file.
#[cfg(any(
feature = "serde",
feature = "bincode_1_3",
feature = "bincode_2_rc",
feature = "postcard_1_0"
))]
mod codec;
#[cfg(any(
feature = "serde",
feature = "bincode_1_3",
feature = "bincode_2_rc",
feature = "postcard_1_0"
))]
pub use codec::*;
mod header;
mod model;
pub mod wrapper;
pub use codec::*;
pub use model::*;
/// Macro to generate a [`native_model`] implementation for a struct.

View File

@@ -5,9 +5,16 @@ edition = "2021"
[workspace]
[dev-dependencies]
native_model = { path = "../" }
serde = { version = "1.0", features = ["derive"] }
bincode = { version = "2.0.0-rc.3", features = ["serde"] }
[dependencies]
native_model = { path = "../", no-default-features = true }
serde = { version = "1.0", features = ["derive"], optional = true }
bincode = { version = "2.0.0-rc.3", features = ["serde"] , optional = true }
postcard = { version = "1.0", features = ["alloc"], optional = true }
anyhow = "1.0"
postcard = { version = "1.0", features = ["alloc"] }
[features]
default = ["bincode_1_3"]
bincode_1_3 = ["serde", "native_model/bincode_1_3"]
bincode_2_rc = ["serde", "native_model/bincode_2_rc", "bincode"]
postcard_1_0 = ["serde", "native_model/postcard_1_0", "postcard"]

View File

@@ -1,344 +0,0 @@
use bincode::{config, Decode, Encode};
use native_model::Result;
use native_model::{DecodeBodyError, DecodeResult, EncodeBodyError, EncodeResult, Model};
// Add this function to the macro for custom serialization
fn native_model_encode<T: Encode>(obj: &T) -> anyhow::Result<Vec<u8>> {
let result = bincode::encode_to_vec(obj, config::standard())?;
Ok(result)
}
// Add this function to the macro for custom deserialization
fn native_model_decode<T: Decode>(data: Vec<u8>) -> anyhow::Result<T> {
let (result, _) =
bincode::decode_from_slice(&data, config::standard()).map_err(|e| EncodeBodyError {
msg: format!("Decode error: {}", e),
source: e.into(),
})?;
Ok(result)
}
#[derive(Debug, Encode, Decode)]
struct A {}
impl Model for A {
fn native_model_id() -> u32 {
1
}
fn native_model_version() -> u32 {
1
}
fn native_model_decode_upgrade_body(_data: Vec<u8>, _id: u32, version: u32) -> Result<Self> {
println!(
"A::deserialization_and_upgrade({}, {})",
version,
Self::native_model_version()
);
if version == Self::native_model_version() {
Ok(Self {})
} else if version < Self::native_model_version() {
panic!("The version {} not supported", version);
} else {
panic!("Not implemented");
}
}
fn native_model_encode_body(&self) -> EncodeResult<Vec<u8>>
where
Self: Sized,
{
native_model_encode(self).map_err(|e| EncodeBodyError {
msg: format!("{}", e),
source: e.into(),
})
}
fn native_model_decode_body(data: Vec<u8>, _id: u32) -> DecodeResult<Self>
where
Self: Sized,
{
native_model_decode(data).map_err(|e| DecodeBodyError::DecodeError {
msg: format!("{}", e),
source: e.into(),
})
}
fn native_model_encode_downgrade_body(self, version: u32) -> Result<Vec<u8>>
where
Self: Sized,
{
println!(
"A::serialization_and_downgrade({}, {})",
version,
Self::native_model_version()
);
if version == Self::native_model_version() {
let result = self.native_model_encode_body()?;
Ok(result)
} else if version < Self::native_model_version() {
panic!("The version {} not supported", version);
} else {
panic!("Not implemented");
}
}
}
#[derive(Debug, Encode, Decode)]
struct B {}
impl Model for B {
fn native_model_id() -> u32 {
1
}
fn native_model_version() -> u32 {
2
}
fn native_model_decode_upgrade_body(_data: Vec<u8>, id: u32, version: u32) -> Result<Self> {
println!(
"B::deserialization_and_upgrade({}, {})",
version,
Self::native_model_version()
);
if version == Self::native_model_version() {
Ok(Self {})
} else if version < Self::native_model_version() {
A::native_model_decode_upgrade_body(_data, id, version).map(|a| a.into())
} else {
panic!("Not implemented");
}
}
fn native_model_encode_body(&self) -> EncodeResult<Vec<u8>>
where
Self: Sized,
{
native_model_encode(self).map_err(|e| EncodeBodyError {
msg: format!("{}", e),
source: e.into(),
})
}
fn native_model_decode_body(data: Vec<u8>, _id: u32) -> DecodeResult<Self>
where
Self: Sized,
{
native_model_decode(data).map_err(|e| DecodeBodyError::DecodeError {
msg: format!("{}", e),
source: e.into(),
})
}
fn native_model_encode_downgrade_body(self, version: u32) -> Result<Vec<u8>>
where
Self: Sized,
{
println!(
"B::serialization_and_downgrade({}, {})",
version,
Self::native_model_version()
);
if version == Self::native_model_version() {
let result = self.native_model_encode_body()?;
Ok(result)
} else if version < Self::native_model_version() {
A::native_model_encode_downgrade_body(self.into(), version)
} else {
panic!("Not implemented");
}
}
}
impl From<B> for A {
fn from(_: B) -> Self {
Self {}
}
}
impl From<A> for B {
fn from(_: A) -> Self {
Self {}
}
}
#[derive(Debug, Encode, Decode)]
struct C {}
impl Model for C {
fn native_model_id() -> u32 {
1
}
fn native_model_version() -> u32 {
3
}
fn native_model_decode_upgrade_body(_data: Vec<u8>, id: u32, version: u32) -> Result<Self> {
println!(
"C::deserialization_and_upgrade({}, {})",
version,
Self::native_model_version()
);
if version == Self::native_model_version() {
Ok(Self {})
} else if version < Self::native_model_version() {
let result = B::native_model_decode_upgrade_body(_data, id, version).map(|b| {
b.try_into()
.map_err(|e: anyhow::Error| native_model::UpgradeError {
msg: format!("{}", e),
source: e.into(),
})
})??;
Ok(result)
} else {
panic!("Not implemented");
}
}
fn native_model_encode_body(&self) -> EncodeResult<Vec<u8>>
where
Self: Sized,
{
native_model_encode(self).map_err(|e| EncodeBodyError {
msg: format!("{}", e),
source: e.into(),
})
}
fn native_model_decode_body(data: Vec<u8>, _id: u32) -> DecodeResult<Self>
where
Self: Sized,
{
native_model_decode(data).map_err(|e| DecodeBodyError::DecodeError {
msg: format!("{}", e),
source: e.into(),
})
}
fn native_model_encode_downgrade_body(self, version: u32) -> Result<Vec<u8>>
where
Self: Sized,
{
println!(
"C::serialization_and_downgrade({}, {})",
version,
Self::native_model_version()
);
if version == Self::native_model_version() {
let result = self.native_model_encode_body()?;
Ok(result)
} else if version < Self::native_model_version() {
let result = B::native_model_encode_downgrade_body(
self.try_into()
.map_err(|e: anyhow::Error| native_model::DowngradeError {
msg: format!("{}", e),
source: e.into(),
})?,
version,
)?;
Ok(result)
} else {
panic!("Not implemented");
}
}
}
impl TryFrom<C> for B {
type Error = anyhow::Error;
fn try_from(_: C) -> anyhow::Result<Self> {
Ok(Self {})
}
}
impl TryFrom<B> for C {
type Error = anyhow::Error;
fn try_from(_: B) -> anyhow::Result<Self> {
Ok(Self {})
}
}
/**
I want to manage the upgrade and downgrade of native types using From and Into traits.
Let see 3 model A,B,C of a model id 1.
A is the oldest version of the model and is the version 1.
B is the intermediate version of the model and is the version 2.
C is the most recent version of the model and is the version 3.
We need to imagine that the data are serialized as a vector of bytes. The only things that we know
is the model id 1 and the version of the model.
I need to found an elegant way to deserialize the data as the most recent version of the model.
**/
#[test]
fn test_encode_downgrade() {
let x = 3;
let result = C::native_model_encode_downgrade_body(C {}, x);
dbg!(&result);
let x = 2;
let result = C::native_model_encode_downgrade_body(C {}, x);
dbg!(&result);
let x = 1;
let result = C::native_model_encode_downgrade_body(C {}, x);
dbg!(&result);
}
#[test]
fn test_decode_upgrade() {
let id = 1;
let version = 3;
let result = C::native_model_decode_upgrade_body(vec![], id, version);
dbg!(&result);
let version = 2;
let result = C::native_model_decode_upgrade_body(vec![], id, version);
dbg!(&result);
let version = 1;
let result = C::native_model_decode_upgrade_body(vec![], id, version);
dbg!(&result);
}
fn native_model_decode_upgrade<T>(
_data: Vec<u8>,
model_id: u32,
version: u32,
) -> native_model::Result<T>
where
T: Model,
{
if model_id == T::native_model_id() {
T::native_model_decode_upgrade_body(_data, model_id, version)
} else {
panic!("The model id {} not supported", model_id);
}
}
#[test]
fn test_decode_upgrade_c() {
let x = 3;
let result: C = native_model_decode_upgrade(vec![], 1, x).unwrap();
dbg!(&result);
let x = 2;
let result: C = native_model_decode_upgrade(vec![], 1, x).unwrap();
dbg!(&result);
let x = 1;
let result: C = native_model_decode_upgrade(vec![], 1, x).unwrap();
dbg!(&result);
}
#[test]
fn test_decode_upgrade_b() {
let x = 2;
let result: B = native_model_decode_upgrade(vec![], 1, x).unwrap();
dbg!(&result);
// let x = 2;
// let result: B = native_model_decode_upgrade(vec![], 1, x).unwrap();
// dbg!(&result);
}

View File

@@ -1,3 +1,4 @@
#![cfg(feature = "bincode_1_3")]
use native_model::native_model;
use serde::Deserialize;
use serde::Serialize;

View File

@@ -1,3 +1,4 @@
#![cfg(feature = "bincode_2_rc")]
use native_model::{native_model};
use serde::Deserialize;
use serde::Serialize;

View File

@@ -1,3 +1,4 @@
#![cfg(feature = "bincode_1_3")]
use native_model::native_model;
use serde::Deserialize;
use serde::Serialize;

View File

@@ -1,3 +1,4 @@
#![cfg(feature = "postcard_1_0")]
use native_model::{native_model};
use serde::Deserialize;
use serde::Serialize;

View File

@@ -1,3 +1,4 @@
#![cfg(feature = "bincode")]
use bincode::{config, Decode, Encode};
use native_model::native_model;

View File

@@ -1,28 +1,13 @@
use bincode;
use bincode::{config, Decode, Encode};
#![cfg(feature = "bincode_1_3")]
use native_model::native_model;
use serde::{Deserialize, Serialize};
pub struct Bincode;
impl<T: bincode::Encode> native_model::Encode<T> for Bincode {
type Error = bincode::error::EncodeError;
fn encode(obj: &T) -> Result<Vec<u8>, bincode::error::EncodeError> {
bincode::encode_to_vec(obj, config::standard())
}
}
impl<T: bincode::Decode> native_model::Decode<T> for Bincode {
type Error = bincode::error::DecodeError;
fn decode(data: Vec<u8>) -> Result<T, bincode::error::DecodeError> {
bincode::decode_from_slice(&data, config::standard()).map(|(result, _)| result)
}
}
#[derive(Encode, Decode, PartialEq, Debug)]
#[native_model(id = 1, version = 1, with = Bincode)]
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[native_model(id = 1, version = 1)]
struct DotV1(u32, u32);
#[derive(Encode, Decode, PartialEq, Debug)]
#[native_model(id = 1, version = 2, with = Bincode, from = DotV1)]
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[native_model(id = 1, version = 2, from = DotV1)]
struct DotV2 {
name: String,
x: u64,

View File

@@ -1,29 +1,16 @@
use bincode::{config, Decode, Encode};
#![cfg(feature = "bincode_1_3")]
use serde::{Deserialize, Serialize};
use native_model::{native_model, Model};
pub struct Bincode;
impl<T: bincode::Encode> native_model::Encode<T> for Bincode {
type Error = bincode::error::EncodeError;
fn encode(obj: &T) -> Result<Vec<u8>, bincode::error::EncodeError> {
bincode::encode_to_vec(obj, config::standard())
}
}
impl<T: bincode::Decode> native_model::Decode<T> for Bincode {
type Error = bincode::error::DecodeError;
fn decode(data: Vec<u8>) -> Result<T, bincode::error::DecodeError> {
bincode::decode_from_slice(&data, config::standard()).map(|(result, _)| result)
}
}
#[derive(Debug, Encode, Decode)]
#[native_model(id = 1, version = 1, with = Bincode)]
#[derive(Debug, Serialize, Deserialize)]
#[native_model(id = 1, version = 1)]
struct Foo1 {
x: i32,
}
#[derive(Debug, Encode, Decode)]
#[native_model(id = 1, version = 2, with = Bincode, from = Foo1)]
#[derive(Debug, Serialize, Deserialize)]
#[native_model(id = 1, version = 2, from = Foo1)]
struct Foo2 {
x: i32,
}

View File

@@ -1,31 +1,16 @@
use bincode::{config, Decode, Encode};
#![cfg(feature = "bincode_1_3")]
use native_model::native_model;
use native_model::Model;
use serde::{Deserialize, Serialize};
pub struct Bincode;
impl<T: bincode::Encode> native_model::Encode<T> for Bincode {
type Error = bincode::error::EncodeError;
fn encode(obj: &T) -> Result<Vec<u8>, bincode::error::EncodeError> {
bincode::encode_to_vec(obj, config::standard())
}
}
impl<T: bincode::Decode> native_model::Decode<T> for Bincode {
type Error = bincode::error::DecodeError;
fn decode(data: Vec<u8>) -> Result<T, bincode::error::DecodeError> {
bincode::decode_from_slice(&data, config::standard()).map(|(result, _)| result)
}
}
#[derive(Debug, Encode, Decode, PartialEq)]
#[native_model(id = 1, version = 1, with = Bincode)]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[native_model(id = 1, version = 1)]
struct Foo1 {
x: i32,
}
#[derive(Debug, Encode, Decode, PartialEq)]
#[native_model(id = 1, version = 2, with = Bincode, from = Foo1)]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[native_model(id = 1, version = 2, from = Foo1)]
struct Foo2 {
x: String,
}
@@ -46,8 +31,8 @@ impl From<Foo2> for Foo1 {
}
}
#[derive(Debug, Encode, Decode, PartialEq)]
#[native_model(id = 1, version = 3, with = Bincode, from = Foo2)]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[native_model(id = 1, version = 3, from = Foo2)]
enum Foo3 {
X(i32),
}
@@ -156,8 +141,8 @@ fn test_should_fail_decode_foo2_to_foo1() {
));
}
#[derive(Debug, Encode, Decode, PartialEq)]
#[native_model(id = 2, version = 1, with = Bincode)]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[native_model(id = 2, version = 1)]
struct Foo1Bis {
x: i32,
}

View File

@@ -1,31 +1,17 @@
use bincode::{config, Decode, Encode};
#![cfg(feature = "bincode_1_3")]
use native_model::native_model;
use native_model::Model;
use serde::{Deserialize, Serialize};
pub struct Bincode;
impl<T: bincode::Encode> native_model::Encode<T> for Bincode {
type Error = bincode::error::EncodeError;
fn encode(obj: &T) -> Result<Vec<u8>, bincode::error::EncodeError> {
bincode::encode_to_vec(obj, config::standard())
}
}
impl<T: bincode::Decode> native_model::Decode<T> for Bincode {
type Error = bincode::error::DecodeError;
fn decode(data: Vec<u8>) -> Result<T, bincode::error::DecodeError> {
bincode::decode_from_slice(&data, config::standard()).map(|(result, _)| result)
}
}
#[derive(Debug, Encode, Decode, PartialEq)]
#[native_model(id = 1, version = 1, with = Bincode)]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[native_model(id = 1, version = 1)]
struct Foo1 {
x: i32,
}
#[derive(Debug, Encode, Decode, PartialEq)]
#[native_model(id = 1, version = 2, with = Bincode, from = Foo1)]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[native_model(id = 1, version = 2, from = Foo1)]
struct Foo2 {
x: i32,
}

View File

@@ -1,27 +1,16 @@
use bincode::{config, Decode, Encode};
use native_model::native_model;
pub struct Bincode;
impl<T: bincode::Encode> native_model::Encode<T> for Bincode {
type Error = bincode::error::EncodeError;
fn encode(obj: &T) -> Result<Vec<u8>, bincode::error::EncodeError> {
bincode::encode_to_vec(obj, config::standard())
}
}
#![cfg(feature = "bincode_1_3")]
impl<T: bincode::Decode> native_model::Decode<T> for Bincode {
type Error = bincode::error::DecodeError;
fn decode(data: Vec<u8>) -> Result<T, bincode::error::DecodeError> {
bincode::decode_from_slice(&data, config::standard()).map(|(result, _)| result)
}
}
#[derive(Debug, Encode, Decode, PartialEq)]
#[native_model(id = 1, version = 1, with = Bincode)]
use native_model::native_model;
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[native_model(id = 1, version = 1)]
struct Foo1 {
x: i32,
}
#[derive(Debug, Encode, Decode, PartialEq)]
#[native_model(id = 1, version = 2, with = Bincode, from = Foo1)]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[native_model(id = 1, version = 2, from = Foo1)]
struct Foo2 {
x: i32,
c: char,
@@ -65,11 +54,11 @@ fn test_decode_foo1_to_foo2() {
fn test_encode_foo2_to_foo1() {
let foo2 = Foo2 { x: 100, c: 'a' };
let foo2_packed = native_model::encode(&foo2).unwrap();
assert_eq!(foo2_packed, vec![1, 0, 0, 0, 2, 0, 0, 0, 200, 97]);
assert_eq!(foo2_packed, vec![1, 0, 0, 0, 2, 0, 0, 0, 100, 0, 0, 0, 97]);
let (foo2_decoded, _) = native_model::decode::<Foo2>(foo2_packed.clone()).unwrap();
assert_eq!(Foo2 { x: 100, c: 'a' }, foo2_decoded);
let foo1_packed = native_model::encode_downgrade(foo2, 1).unwrap();
assert_eq!(foo1_packed, vec![1, 0, 0, 0, 1, 0, 0, 0, 200]);
assert_eq!(foo1_packed, vec![1, 0, 0, 0, 1, 0, 0, 0, 100, 0, 0, 0]);
let (foo1_decoded, _) = native_model::decode::<Foo1>(foo1_packed.clone()).unwrap();
assert_eq!(Foo1 { x: 100 }, foo1_decoded);
}
@@ -78,11 +67,11 @@ fn test_encode_foo2_to_foo1() {
fn test_encode_foo1_to_foo1() {
let foo1 = Foo1 { x: 100 };
let foo1_packed = native_model::encode(&foo1).unwrap();
assert_eq!(foo1_packed, vec![1, 0, 0, 0, 1, 0, 0, 0, 200]);
assert_eq!(foo1_packed, vec![1, 0, 0, 0, 1, 0, 0, 0, 100, 0, 0, 0]);
let (foo1_decoded, _) = native_model::decode::<Foo1>(foo1_packed.clone()).unwrap();
assert_eq!(Foo1 { x: 100 }, foo1_decoded);
let foo1_packed = native_model::encode_downgrade(foo1, 1).unwrap();
assert_eq!(foo1_packed, vec![1, 0, 0, 0, 1, 0, 0, 0, 200]);
assert_eq!(foo1_packed, vec![1, 0, 0, 0, 1, 0, 0, 0, 100, 0, 0, 0]);
let (foo1_decoded, _) = native_model::decode::<Foo1>(foo1_packed.clone()).unwrap();
assert_eq!(Foo1 { x: 100 }, foo1_decoded);
}

View File

@@ -1,29 +1,16 @@
use bincode::{config, Decode, Encode};
#![cfg(feature = "bincode_1_3")]
use native_model::native_model;
use serde::{Deserialize, Serialize};
pub struct Bincode;
impl<T: bincode::Encode> native_model::Encode<T> for Bincode {
type Error = bincode::error::EncodeError;
fn encode(obj: &T) -> Result<Vec<u8>, bincode::error::EncodeError> {
bincode::encode_to_vec(obj, config::standard())
}
}
impl<T: bincode::Decode> native_model::Decode<T> for Bincode {
type Error = bincode::error::DecodeError;
fn decode(data: Vec<u8>) -> Result<T, bincode::error::DecodeError> {
bincode::decode_from_slice(&data, config::standard()).map(|(result, _)| result)
}
}
#[derive(Debug, Encode, Decode, PartialEq)]
#[native_model(id = 1, version = 1, with = Bincode)]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[native_model(id = 1, version = 1)]
struct Foo1 {
x: i32,
}
#[derive(Debug, Encode, Decode, PartialEq)]
#[native_model(id = 1, version = 2, with = Bincode, try_from = (Foo1, anyhow::Error))]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[native_model(id = 1, version = 2, try_from = (Foo1, anyhow::Error))]
struct Foo2 {
x: i32,
}