Bincode 1 compatibility framework (#489)
* 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
This commit is contained in:
parent
9535e7b5da
commit
00eea110d7
|
|
@ -1,6 +1,7 @@
|
|||
[workspace]
|
||||
members = [
|
||||
"derive"
|
||||
"derive",
|
||||
"compatibility"
|
||||
]
|
||||
|
||||
[package]
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue