diff --git a/Cargo.toml b/Cargo.toml index 6b7ceeb8..7efb70be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = [ - "derive" + "derive", + "compatibility" ] [package] diff --git a/compatibility/Cargo.toml b/compatibility/Cargo.toml new file mode 100644 index 00000000..10d945e9 --- /dev/null +++ b/compatibility/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "bincode_compatibility" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +bincode_2 = { path = "..", package = "bincode" } +bincode_1 = { version = "1", package = "bincode" } +serde = { version = "1", features = ["derive"] } +rand = "0.8" diff --git a/compatibility/src/lib.rs b/compatibility/src/lib.rs new file mode 100644 index 00000000..419745df --- /dev/null +++ b/compatibility/src/lib.rs @@ -0,0 +1,107 @@ +#![cfg(test)] + +use ::rand::Rng; +use bincode_1::Options; + +mod rand; +mod sway; + +pub fn test_same_with_config(t: &T, bincode_1_options: O, bincode_2_config: C) +where + T: bincode_2::Encode + + bincode_2::Decode + + serde::Serialize + + serde::de::DeserializeOwned + + core::fmt::Debug + + PartialEq, + C: bincode_2::config::Config, + O: bincode_1::Options + Copy, +{ + let bincode_1_output = bincode_1_options.serialize(t).unwrap(); + let bincode_2_output = bincode_2::encode_to_vec(t, bincode_2_config).unwrap(); + + assert_eq!( + bincode_1_output, bincode_2_output, + "{:?} serializes differently", + t + ); + + let decoded: T = bincode_1_options.deserialize(&bincode_1_output).unwrap(); + assert_eq!(&decoded, t); + let decoded: T = bincode_1_options.deserialize(&bincode_2_output).unwrap(); + assert_eq!(&decoded, t); + + let decoded: T = bincode_2::decode_from_slice(&bincode_1_output, bincode_2_config) + .unwrap() + .0; + assert_eq!(&decoded, t); + let decoded: T = bincode_2::decode_from_slice(&bincode_2_output, bincode_2_config) + .unwrap() + .0; + assert_eq!(&decoded, t); +} + +pub fn test_same(t: T) +where + T: bincode_2::Encode + + bincode_2::Decode + + serde::Serialize + + serde::de::DeserializeOwned + + core::fmt::Debug + + PartialEq, +{ + test_same_with_config( + &t, + // This is the config used internally by bincode 1 + bincode_1::options().with_fixint_encoding(), + // Should match `::legacy()` + bincode_2::config::legacy(), + ); + + // Check a bunch of different configs: + test_same_with_config( + &t, + bincode_1::options() + .with_big_endian() + .with_varint_encoding(), + bincode_2::config::legacy() + .with_big_endian() + .with_variable_int_encoding(), + ); + test_same_with_config( + &t, + bincode_1::options() + .with_little_endian() + .with_varint_encoding(), + bincode_2::config::legacy() + .with_little_endian() + .with_variable_int_encoding(), + ); + test_same_with_config( + &t, + bincode_1::options() + .with_big_endian() + .with_fixint_encoding(), + bincode_2::config::legacy() + .with_big_endian() + .with_fixed_int_encoding(), + ); + test_same_with_config( + &t, + bincode_1::options() + .with_little_endian() + .with_fixint_encoding(), + bincode_2::config::legacy() + .with_little_endian() + .with_fixed_int_encoding(), + ); +} + +pub fn gen_string(rng: &mut impl Rng) -> String { + let len = rng.gen_range(0..100usize); + let mut result = String::with_capacity(len * 4); + for _ in 0..len { + result.push(rng.gen_range('\0'..char::MAX)); + } + result +} diff --git a/compatibility/src/rand.rs b/compatibility/src/rand.rs new file mode 100644 index 00000000..cb0f4f01 --- /dev/null +++ b/compatibility/src/rand.rs @@ -0,0 +1,25 @@ +// Simplified case, taken from: +// https://github.com/rust-random/rand/blob/19404d68764ed08513131f82157e2ccad69dcf83/rand_pcg/src/pcg64.rs#L37-L40 +// Original license: MIT OR Apache-2.0 + +use rand::Rng; + +#[derive( + Debug, bincode_2::Encode, bincode_2::Decode, serde::Serialize, serde::Deserialize, PartialEq, +)] +#[bincode(crate = "bincode_2")] +pub struct Lcg64Xsh32 { + state: u64, + increment: u64, +} + +#[test] +pub fn test() { + let mut rng = rand::thread_rng(); + for _ in 0..1000 { + crate::test_same(Lcg64Xsh32 { + state: rng.gen(), + increment: rng.gen(), + }); + } +} diff --git a/compatibility/src/sway.rs b/compatibility/src/sway.rs new file mode 100644 index 00000000..c01d0f23 --- /dev/null +++ b/compatibility/src/sway.rs @@ -0,0 +1,85 @@ +// Credits to Sway in the Rust Programming Language + +use rand::Rng; +use serde::{Deserialize, Serialize}; + +#[test] +pub fn test() { + let mut rng = rand::thread_rng(); + for _ in 0..1000 { + crate::test_same(random(&mut rng)); + } +} + +fn random(rng: &mut impl Rng) -> FTXresponse { + if rng.gen() { + FTXresponse::Result(FTXresponseSuccess { + result: Trade::random(rng), + success: rng.gen(), + }) + } else { + FTXresponse::Error(FTXresponseFailure { + success: rng.gen(), + error: crate::gen_string(rng), + }) + } +} + +#[derive(bincode_2::Encode, bincode_2::Decode, Serialize, Deserialize, Debug, PartialEq)] +#[bincode(crate = "bincode_2")] +pub enum FTXresponse { + Result(FTXresponseSuccess), + Error(FTXresponseFailure), +} + +#[derive( + bincode_2::Encode, bincode_2::Decode, serde::Serialize, serde::Deserialize, Debug, PartialEq, +)] +#[bincode(crate = "bincode_2")] +pub struct FTXresponseSuccess { + pub success: bool, + pub result: T, +} + +#[derive(bincode_2::Encode, bincode_2::Decode, Serialize, Deserialize, Debug, PartialEq)] +#[bincode(crate = "bincode_2")] +pub struct FTXresponseFailure { + pub success: bool, + pub error: String, +} + +#[derive(bincode_2::Encode, bincode_2::Decode, Serialize, Deserialize, Debug, PartialEq)] +#[bincode(crate = "bincode_2")] +pub enum TradeSide { + Buy, + Sell, +} + +#[derive(bincode_2::Encode, bincode_2::Decode, Serialize, Deserialize, Debug, PartialEq)] +#[bincode(crate = "bincode_2")] +#[serde(rename_all = "camelCase")] +pub struct Trade { + pub id: u64, + pub liquidation: bool, + pub price: f64, + pub side: TradeSide, + pub size: f64, + pub time: String, +} + +impl Trade { + fn random(rng: &mut impl Rng) -> Self { + Self { + id: rng.gen(), + liquidation: rng.gen(), + price: rng.gen(), + side: if rng.gen() { + TradeSide::Buy + } else { + TradeSide::Sell + }, + size: rng.gen(), + time: crate::gen_string(rng), + } + } +}