Skip to content

Commit

Permalink
Bincode 1 compatibility framework (#489)
Browse files Browse the repository at this point in the history
* Added a basic compatibility test to compare bincode 1 and bincode 2 output

* Moved compatibility to the /compatibility/ crate, made bincode-derive support `#[bincode(crate = "bincode_2")]`

* Added decode/deserialize test to test_same

* Added random test cases to compatibility/src/sway.rs

* Added test for bincode_1::options().with_fixint_encoding() and bincode_2::config::legacy(). Added rand license

* Added comments on why the configs are chosen
  • Loading branch information
VictorKoenders authored Feb 1, 2022
1 parent 4d12ecc commit 9d70b8c
Show file tree
Hide file tree
Showing 5 changed files with 231 additions and 1 deletion.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[workspace]
members = [
"derive"
"derive",
"compatibility"
]

[package]
Expand Down
12 changes: 12 additions & 0 deletions compatibility/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"
107 changes: 107 additions & 0 deletions compatibility/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#![cfg(test)]

use ::rand::Rng;
use bincode_1::Options;

mod rand;
mod sway;

pub fn test_same_with_config<T, C, O>(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: 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
}
25 changes: 25 additions & 0 deletions compatibility/src/rand.rs
Original file line number Diff line number Diff line change
@@ -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(),
});
}
}
85 changes: 85 additions & 0 deletions compatibility/src/sway.rs
Original file line number Diff line number Diff line change
@@ -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<Trade> {
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<T> {
Result(FTXresponseSuccess<T>),
Error(FTXresponseFailure),
}

#[derive(
bincode_2::Encode, bincode_2::Decode, serde::Serialize, serde::Deserialize, Debug, PartialEq,
)]
#[bincode(crate = "bincode_2")]
pub struct FTXresponseSuccess<T> {
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),
}
}
}

0 comments on commit 9d70b8c

Please sign in to comment.