From 077fc7fd48f3389f1452bbfc2c6348a978e0fcb9 Mon Sep 17 00:00:00 2001 From: Victor Koenders Date: Sun, 23 Jan 2022 11:42:35 +0100 Subject: [PATCH] Moved compatibility to the /compatibility/ crate, made bincode-derive support `#[bincode(crate = "bincode_2")]` --- Cargo.toml | 4 +- compatibility/Cargo.toml | 12 ++++ compatibility/src/lib.rs | 64 +++++++++++++++++++++ compatibility/src/rand.rs | 22 ++++++++ compatibility/src/sway.rs | 44 +++++++++++++++ derive/Cargo.toml | 2 +- derive/src/derive_enum.rs | 94 ++++++++++++++++++++----------- derive/src/derive_struct.rs | 59 +++++++++++--------- derive/src/lib.rs | 108 +++++++++++++++++++++++++++++++++--- tests/compatibility.rs | 58 ------------------- 10 files changed, 340 insertions(+), 127 deletions(-) create mode 100644 compatibility/Cargo.toml create mode 100644 compatibility/src/lib.rs create mode 100644 compatibility/src/rand.rs create mode 100644 compatibility/src/sway.rs delete mode 100644 tests/compatibility.rs diff --git a/Cargo.toml b/Cargo.toml index d5cefc4d..7efb70be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = [ - "derive" + "derive", + "compatibility" ] [package] @@ -51,7 +52,6 @@ criterion = "0.3" rand = "0.8" uuid = { version = "0.8", features = ["serde"] } chrono = { version = "0.4", features = ["serde"] } -bincode1 = { version = "1.0", package = "bincode" } [[bench]] name = "varint" 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..b09857cb --- /dev/null +++ b/compatibility/src/lib.rs @@ -0,0 +1,64 @@ +#![cfg(test)] + +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 + serde::Serialize + core::fmt::Debug, + C: bincode_2::config::Config + Clone, + O: bincode_1::Options + Clone, +{ + 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 + ); +} + +pub fn test_same(t: T) +where + T: bincode_2::Encode + serde::Serialize + core::fmt::Debug, +{ + 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(), + ); +} diff --git a/compatibility/src/rand.rs b/compatibility/src/rand.rs new file mode 100644 index 00000000..baa575d4 --- /dev/null +++ b/compatibility/src/rand.rs @@ -0,0 +1,22 @@ +// Simplified case, taken from: +// https://github.com/rust-random/rand/blob/19404d68764ed08513131f82157e2ccad69dcf83/rand_pcg/src/pcg64.rs#L37-L40 + +use rand::Rng; + +#[derive(Debug, bincode_2::Encode, bincode_2::Decode, serde::Serialize, serde::Deserialize)] +#[bincode(crate = "bincode_2")] +pub struct Lcg64Xsh32 { + state: u64, + increment: u64, +} + +#[test] +pub fn test() { + let mut rng = rand::thread_rng(); + for _ in 0..100 { + 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..e4348c2e --- /dev/null +++ b/compatibility/src/sway.rs @@ -0,0 +1,44 @@ +// Credits to Sway in the Rust Programming Language + +use serde::{Deserialize, Serialize}; + +#[derive(bincode_2::Encode, bincode_2::Decode, serde::Serialize, serde::Deserialize, Debug)] +#[bincode(crate = "bincode_2")] +pub struct FTXresponseSuccess { + pub success: bool, + pub result: T, +} + +#[derive(bincode_2::Encode, bincode_2::Decode, Serialize, Deserialize, Debug)] +#[bincode(crate = "bincode_2")] +pub struct FTXresponseFailure { + pub success: bool, + pub error: String, +} + +#[derive(bincode_2::Encode, bincode_2::Decode, Serialize, Deserialize, Debug)] +#[bincode(crate = "bincode_2")] +#[serde(untagged)] +pub enum FTXresponse { + Result(FTXresponseSuccess), + Error(FTXresponseFailure), +} + +#[derive(bincode_2::Encode, bincode_2::Decode, Serialize, Deserialize, Debug)] +#[bincode(crate = "bincode_2")] +pub enum TradeSide { + Buy, + Sell, +} + +#[derive(bincode_2::Encode, bincode_2::Decode, Serialize, Deserialize, Debug)] +#[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, +} diff --git a/derive/Cargo.toml b/derive/Cargo.toml index f573e24b..8af51423 100644 --- a/derive/Cargo.toml +++ b/derive/Cargo.toml @@ -16,4 +16,4 @@ description = "Implementation of #[derive(Encode, Decode)] for bincode" proc-macro = true [dependencies] -virtue = "0.0.4" +virtue = "0.0.5" diff --git a/derive/src/derive_enum.rs b/derive/src/derive_enum.rs index 2b643a69..ee5af6c1 100644 --- a/derive/src/derive_enum.rs +++ b/derive/src/derive_enum.rs @@ -1,12 +1,14 @@ use super::FieldAttribute; +use crate::CrateNameAttribute; use virtue::generate::{FnSelfArg, Generator, StreamBuilder}; use virtue::parse::{EnumVariant, Fields}; use virtue::prelude::*; const TUPLE_FIELD_PREFIX: &str = "field_"; -pub struct DeriveEnum { +pub(crate) struct DeriveEnum { pub variants: Vec, + pub crate_name: CrateNameAttribute, } impl DeriveEnum { @@ -20,17 +22,22 @@ impl DeriveEnum { pub fn generate_encode(self, generator: &mut Generator) -> Result<()> { generator - .impl_for("bincode::Encode")? + .impl_for(self.crate_name.ty("Encode"))? .modify_generic_constraints(|generics, where_constraints| { for g in generics.iter_generics() { - where_constraints.push_constraint(g, "bincode::Encode").unwrap(); + where_constraints + .push_constraint(g, self.crate_name.ty("Encode")) + .unwrap(); } }) .generate_fn("encode") - .with_generic("E", ["bincode::enc::Encoder"]) + .with_generic_deps("E", [self.crate_name.ty("enc::Encoder")]) .with_self_arg(FnSelfArg::RefSelf) .with_arg("encoder", "&mut E") - .with_return_type("core::result::Result<(), bincode::error::EncodeError>") + .with_return_type(format!( + "core::result::Result<(), {}::error::EncodeError>", + self.crate_name.name + )) .body(|fn_body| { fn_body.ident_str("match"); fn_body.ident_str("self"); @@ -76,7 +83,10 @@ impl DeriveEnum { // } match_body.group(Delimiter::Brace, |body| { // variant index - body.push_parsed("::encode")?; + body.push_parsed(format!( + "::encode", + self.crate_name.name + ))?; body.group(Delimiter::Parenthesis, |args| { args.punct('&'); args.group(Delimiter::Parenthesis, |num| { @@ -91,17 +101,21 @@ impl DeriveEnum { body.punct(';'); // If we have any fields, encode them all one by one for field_name in variant.fields.names() { - if field_name.attributes().has_attribute(FieldAttribute::WithSerde)? { + if field_name + .attributes() + .has_attribute(FieldAttribute::WithSerde)? + { body.push_parsed(format!( - "bincode::Encode::encode(&bincode::serde::Compat({}), encoder)?;", + "{0}::Encode::encode(&{0}::serde::Compat({1}), encoder)?;", + self.crate_name.name, field_name.to_string_with_prefix(TUPLE_FIELD_PREFIX), ))?; } else { body.push_parsed(format!( - "bincode::Encode::encode({}, encoder)?;", + "{0}::Encode::encode({1}, encoder)?;", + self.crate_name.name, field_name.to_string_with_prefix(TUPLE_FIELD_PREFIX), - )) - ?; + ))?; } } body.push_parsed("Ok(())")?; @@ -142,7 +156,7 @@ impl DeriveEnum { result.puncts("=>"); result.ident_str("Err"); result.group(Delimiter::Parenthesis, |err_inner| { - err_inner.push_parsed("bincode::error::DecodeError::UnexpectedVariant")?; + err_inner.push_parsed(self.crate_name.ty("error::DecodeError::UnexpectedVariant"))?; err_inner.group(Delimiter::Brace, |variant_inner| { variant_inner.ident_str("found"); variant_inner.punct(':'); @@ -159,7 +173,8 @@ impl DeriveEnum { if self.variants.iter().any(|i| i.has_fixed_value()) { // we have fixed values, implement AllowedEnumVariants::Allowed - variant_inner.push_parsed("bincode::error::AllowedEnumVariants::Allowed")?; + variant_inner + .push_parsed(self.crate_name.ty("error::AllowedEnumVariants::Allowed"))?; variant_inner.group(Delimiter::Parenthesis, |allowed_inner| { allowed_inner.punct('&'); allowed_inner.group(Delimiter::Bracket, |allowed_slice| { @@ -176,7 +191,8 @@ impl DeriveEnum { } else { // no fixed values, implement a range variant_inner.push_parsed(format!( - "bincode::error::AllowedEnumVariants::Range {{ min: 0, max: {} }}", + "{0}::error::AllowedEnumVariants::Range {{ min: 0, max: {1} }}", + self.crate_name.name, self.variants.len() - 1 ))?; } @@ -193,24 +209,28 @@ impl DeriveEnum { let enum_name = generator.target_name().to_string(); generator - .impl_for("bincode::Decode")? + .impl_for(self.crate_name.ty("Decode"))? .modify_generic_constraints(|generics, where_constraints| { for g in generics.iter_generics() { - where_constraints.push_constraint(g, "bincode::Decode").unwrap(); + where_constraints.push_constraint(g, self.crate_name.ty("Decode")).unwrap(); } }) .generate_fn("decode") - .with_generic("D", ["bincode::de::Decoder"]) + .with_generic_deps("D", [self.crate_name.ty("de::Decoder")]) .with_arg("decoder", "&mut D") - .with_return_type("core::result::Result") + .with_return_type(format!("core::result::Result", self.crate_name.name)) .body(|fn_builder| { if self.variants.is_empty() { - fn_builder.push_parsed("core::result::Result::Err(bincode::error::DecodeError::EmptyEnum { type_name: core::any::type_name::() })")?; + fn_builder.push_parsed(format!( + "core::result::Result::Err({}::error::DecodeError::EmptyEnum {{ type_name: core::any::type_name::() }})", + self.crate_name.name + ))?; } else { fn_builder - .push_parsed( - "let variant_index = ::decode(decoder)?;", - )?; + .push_parsed(format!( + "let variant_index = ::decode(decoder)?;", + self.crate_name.name + ))?; fn_builder.push_parsed("match variant_index")?; fn_builder.group(Delimiter::Brace, |variant_case| { for (mut variant_index, variant) in self.iter_fields() { @@ -242,10 +262,16 @@ impl DeriveEnum { variant_body.punct(':'); if field.attributes().has_attribute(FieldAttribute::WithSerde)? { variant_body - .push_parsed(" as bincode::Decode>::decode(decoder)?.0,")?; + .push_parsed(format!( + "<{0}::serde::Compat<_> as {0}::Decode>::decode(decoder)?.0,", + self.crate_name.name + ))?; } else { variant_body - .push_parsed("bincode::Decode::decode(decoder)?,")?; + .push_parsed(format!( + "{}::Decode::decode(decoder)?,", + self.crate_name.name + ))?; } } Ok(()) @@ -266,25 +292,29 @@ impl DeriveEnum { pub fn generate_borrow_decode(self, generator: &mut Generator) -> Result<()> { // Remember to keep this mostly in sync with generate_decode + let crate_name = &self.crate_name; let enum_name = generator.target_name().to_string(); - generator.impl_for_with_lifetimes("bincode::BorrowDecode", &["__de"])? + generator.impl_for_with_lifetimes(crate_name.ty("BorrowDecode"), ["__de"])? .modify_generic_constraints(|generics, where_constraints| { for g in generics.iter_generics() { - where_constraints.push_constraint(g, "bincode::enc::BorrowDecode").unwrap(); + where_constraints.push_constraint(g, crate_name.ty("enc::BorrowDecode")).unwrap(); } }) .generate_fn("borrow_decode") - .with_generic("D", ["bincode::de::BorrowDecoder<'__de>"]) + .with_generic_deps("D", [crate_name.ty("de::BorrowDecoder<'__de>")]) .with_arg("decoder", "&mut D") - .with_return_type("core::result::Result") + .with_return_type(format!("core::result::Result", crate_name.name)) .body(|fn_builder| { if self.variants.is_empty() { - fn_builder.push_parsed("core::result::Result::Err(bincode::error::DecodeError::EmptyEnum { type_name: core::any::type_name::() })")?; + fn_builder.push_parsed(format!( + "core::result::Result::Err({}::error::DecodeError::EmptyEnum {{ type_name: core::any::type_name::() }})", + crate_name.name + ))?; } else { fn_builder - .push_parsed("let variant_index = ::decode(decoder)?;")?; + .push_parsed(format!("let variant_index = ::decode(decoder)?;", crate_name.name))?; fn_builder.push_parsed("match variant_index")?; fn_builder.group(Delimiter::Brace, |variant_case| { for (mut variant_index, variant) in self.iter_fields() { @@ -316,9 +346,9 @@ impl DeriveEnum { variant_body.punct(':'); if field.attributes().has_attribute(FieldAttribute::WithSerde)? { variant_body - .push_parsed(" as bincode::BorrowDecode>::borrow_decode(decoder)?.0,")?; + .push_parsed(format!("<{0}::serde::BorrowCompat<_> as {0}::BorrowDecode>::borrow_decode(decoder)?.0,", crate_name.name))?; } else { - variant_body.push_parsed("bincode::BorrowDecode::borrow_decode(decoder)?,")?; + variant_body.push_parsed(format!("{}::BorrowDecode::borrow_decode(decoder)?,", crate_name.name))?; } } Ok(()) diff --git a/derive/src/derive_struct.rs b/derive/src/derive_struct.rs index 474afa70..714c02f1 100644 --- a/derive/src/derive_struct.rs +++ b/derive/src/derive_struct.rs @@ -1,30 +1,35 @@ use super::FieldAttribute; +use crate::CrateNameAttribute; use virtue::generate::Generator; use virtue::parse::Fields; use virtue::prelude::*; -pub struct DeriveStruct { +pub(crate) struct DeriveStruct { pub fields: Fields, + pub crate_name: CrateNameAttribute, } impl DeriveStruct { pub fn generate_encode(self, generator: &mut Generator) -> Result<()> { - let DeriveStruct { fields } = self; + let DeriveStruct { fields, crate_name } = self; generator - .impl_for("bincode::Encode")? + .impl_for(&crate_name.ty("Encode"))? .modify_generic_constraints(|generics, where_constraints| { for g in generics.iter_generics() { where_constraints - .push_constraint(g, "bincode::Encode") + .push_constraint(g, crate_name.ty("Encode")) .unwrap(); } }) .generate_fn("encode") - .with_generic("E", ["bincode::enc::Encoder"]) + .with_generic_deps("E", [crate_name.ty("enc::Encoder")]) .with_self_arg(virtue::generate::FnSelfArg::RefSelf) .with_arg("encoder", "&mut E") - .with_return_type("core::result::Result<(), bincode::error::EncodeError>") + .with_return_type(format!( + "core::result::Result<(), {}::error::EncodeError>", + crate_name.name + )) .body(|fn_body| { for field in fields.names() { if field @@ -32,13 +37,13 @@ impl DeriveStruct { .has_attribute(FieldAttribute::WithSerde)? { fn_body.push_parsed(format!( - "bincode::Encode::encode(&bincode::serde::Compat(&self.{}), encoder)?;", - field + "::{0}::Encode::encode(&{0}::serde::Compat(&self.{1}), encoder)?;", + crate_name.name, field ))?; } else { fn_body.push_parsed(format!( - "bincode::Encode::encode(&self.{}, encoder)?;", - field + "::{}::Encode::encode(&self.{}, encoder)?;", + crate_name.name, field ))?; } } @@ -50,19 +55,19 @@ impl DeriveStruct { pub fn generate_decode(self, generator: &mut Generator) -> Result<()> { // Remember to keep this mostly in sync with generate_borrow_decode - let DeriveStruct { fields } = self; + let DeriveStruct { fields, crate_name } = self; generator - .impl_for("bincode::Decode")? + .impl_for(crate_name.ty("Decode"))? .modify_generic_constraints(|generics, where_constraints| { for g in generics.iter_generics() { - where_constraints.push_constraint(g, "bincode::Decode").unwrap(); + where_constraints.push_constraint(g, crate_name.ty("Decode")).unwrap(); } }) .generate_fn("decode") - .with_generic("D", ["bincode::de::Decoder"]) + .with_generic_deps("D", [crate_name.ty("de::Decoder")]) .with_arg("decoder", "&mut D") - .with_return_type("core::result::Result") + .with_return_type(format!("core::result::Result", crate_name.name)) .body(|fn_body| { // Ok(Self { fn_body.ident_str("Ok"); @@ -79,13 +84,15 @@ impl DeriveStruct { if field.attributes().has_attribute(FieldAttribute::WithSerde)? { struct_body .push_parsed(format!( - "{}: ( as bincode::Decode>::decode(decoder)?).0,", + "{1}: (<{0}::serde::Compat<_> as {0}::Decode>::decode(decoder)?).0,", + crate_name.name, field ))?; } else { struct_body .push_parsed(format!( - "{}: bincode::Decode::decode(decoder)?,", + "{1}: {0}::Decode::decode(decoder)?,", + crate_name.name, field ))?; } @@ -101,19 +108,19 @@ impl DeriveStruct { pub fn generate_borrow_decode(self, generator: &mut Generator) -> Result<()> { // Remember to keep this mostly in sync with generate_decode - let DeriveStruct { fields } = self; + let DeriveStruct { fields, crate_name } = self; generator - .impl_for_with_lifetimes("bincode::BorrowDecode", &["__de"])? + .impl_for_with_lifetimes(crate_name.ty("BorrowDecode"), ["__de"])? .modify_generic_constraints(|generics, where_constraints| { for g in generics.iter_generics() { - where_constraints.push_constraint(g, "bincode::BorrowDecode").unwrap(); + where_constraints.push_constraint(g, crate_name.ty("BorrowDecode")).unwrap(); } }) .generate_fn("borrow_decode") - .with_generic("D", ["bincode::de::BorrowDecoder<'__de>"]) + .with_generic_deps("D", [crate_name.ty("de::BorrowDecoder<'__de>")]) .with_arg("decoder", "&mut D") - .with_return_type("core::result::Result") + .with_return_type(format!("core::result::Result", crate_name.name)) .body(|fn_body| { // Ok(Self { fn_body.ident_str("Ok"); @@ -124,13 +131,15 @@ impl DeriveStruct { if field.attributes().has_attribute(FieldAttribute::WithSerde)? { struct_body .push_parsed(format!( - "{}: ( as bincode::BorrowDecode>::borrow_decode(decoder)?).0,", + "{1}: (<{0}::serde::BorrowCompat<_> as {0}::BorrowDecode>::borrow_decode(decoder)?).0,", + crate_name.name, field ))?; } else { struct_body .push_parsed(format!( - "{}: bincode::BorrowDecode::borrow_decode(decoder)?,", + "{1}: {0}::BorrowDecode::borrow_decode(decoder)?,", + crate_name.name, field ))?; } @@ -139,7 +148,7 @@ impl DeriveStruct { })?; Ok(()) })?; - Ok(()) + Ok(()) })?; Ok(()) } diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 806dbd00..6092afca 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -1,7 +1,7 @@ mod derive_enum; mod derive_struct; -use virtue::prelude::*; +use virtue::{prelude::*, utils::parse_tagged_attribute}; #[proc_macro_derive(Encode, attributes(bincode))] pub fn derive_encode(input: proc_macro::TokenStream) -> proc_macro::TokenStream { @@ -10,18 +10,23 @@ pub fn derive_encode(input: proc_macro::TokenStream) -> proc_macro::TokenStream fn derive_encode_inner(input: TokenStream) -> Result { let parse = Parse::new(input)?; - let (mut generator, body) = parse.into_generator(); + let (mut generator, attributes, body) = parse.into_generator(); + let crate_name = attributes + .get_attribute::()? + .unwrap_or_default(); match body { Body::Struct(body) => { derive_struct::DeriveStruct { fields: body.fields, + crate_name, } .generate_encode(&mut generator)?; } Body::Enum(body) => { derive_enum::DeriveEnum { variants: body.variants, + crate_name, } .generate_encode(&mut generator)?; } @@ -40,18 +45,23 @@ pub fn derive_decode(input: proc_macro::TokenStream) -> proc_macro::TokenStream fn derive_decode_inner(input: TokenStream) -> Result { let parse = Parse::new(input)?; - let (mut generator, body) = parse.into_generator(); + let (mut generator, attributes, body) = parse.into_generator(); + let crate_name = attributes + .get_attribute::()? + .unwrap_or_default(); match body { Body::Struct(body) => { derive_struct::DeriveStruct { fields: body.fields, + crate_name, } .generate_decode(&mut generator)?; } Body::Enum(body) => { derive_enum::DeriveEnum { variants: body.variants, + crate_name, } .generate_decode(&mut generator)?; } @@ -70,18 +80,23 @@ pub fn derive_brrow_decode(input: proc_macro::TokenStream) -> proc_macro::TokenS fn derive_borrow_decode_inner(input: TokenStream) -> Result { let parse = Parse::new(input)?; - let (mut generator, body) = parse.into_generator(); + let (mut generator, attributes, body) = parse.into_generator(); + let crate_name = attributes + .get_attribute::()? + .unwrap_or_default(); match body { Body::Struct(body) => { derive_struct::DeriveStruct { fields: body.fields, + crate_name, } .generate_borrow_decode(&mut generator)?; } Body::Enum(body) => { derive_enum::DeriveEnum { variants: body.variants, + crate_name, } .generate_borrow_decode(&mut generator)?; } @@ -98,11 +113,20 @@ fn dump_output(name: Ident, derive: &str, stream: &TokenStream) { if let Ok(var) = std::env::var("CARGO_MANIFEST_DIR") { let mut path = std::path::PathBuf::from(var); - path.push("target"); - if path.exists() { - path.push(format!("{}_{}.rs", name, derive)); - if let Ok(mut file) = std::fs::File::create(path) { - let _ = file.write_all(stream.to_string().as_bytes()); + loop { + { + let mut path = path.clone(); + path.push("target"); + if path.exists() { + path.push(format!("{}_{}.rs", name, derive)); + if let Ok(mut file) = std::fs::File::create(path) { + let _ = file.write_all(stream.to_string().as_bytes()); + } + break; + } + } + if let Some(parent) = path.parent() { + path = parent.to_owned(); } } } @@ -130,3 +154,69 @@ impl FromAttribute for FieldAttribute { } } } + +pub(crate) struct CrateNameAttribute { + pub name: String, +} + +impl CrateNameAttribute { + pub fn ty(&self, ty: &str) -> String { + format!("::{}::{}", self.name, ty) + } +} + +impl Default for CrateNameAttribute { + fn default() -> Self { + Self { + name: String::from("bincode"), + } + } +} + +impl FromAttribute for CrateNameAttribute { + fn parse(group: &Group) -> Result> { + let stream: TokenStream = match parse_tagged_attribute(group, "bincode") { + None => return Ok(None), + Some(s) => s, + }; + let mut iter = stream.into_iter(); + while let Some(item) = iter.next() { + if let TokenTree::Ident(ident) = item { + if ident.to_string() == "crate" { + try_consume_char(&mut iter, '=')?; + return match iter.next() { + Some(TokenTree::Literal(lit)) => { + let crate_name = lit.to_string(); + if !crate_name.starts_with('"') && !crate_name.ends_with('"') { + Err(virtue::Error::Custom { + error: format!("Expected string, found {:?}", lit), + span: Some(lit.span()), + }) + } else { + Ok(Some(Self { + name: crate_name[1..crate_name.len() - 1].to_string(), + })) + } + } + t => Err(virtue::Error::Custom { + error: format!("Expected crate name, found {:?}", t), + span: t.map(|t| t.span()), + }), + }; + } + } + } + + Ok(None) + } +} + +fn try_consume_char(iter: &mut impl Iterator, char: char) -> Result<()> { + match iter.next() { + Some(TokenTree::Punct(p)) if p.as_char() == char => Ok(()), + t => Err(virtue::Error::Custom { + error: format!("Expected `key = val`, found {:?}", t), + span: t.map(|t| t.span()), + }), + } +} diff --git a/tests/compatibility.rs b/tests/compatibility.rs deleted file mode 100644 index 58ce5c4c..00000000 --- a/tests/compatibility.rs +++ /dev/null @@ -1,58 +0,0 @@ -#![cfg(all(feature = "serde", feature = "alloc"))] - -use bincode1::Options; -use rand::Rng; - -fn test_same_with_config(t: &T, bincode_1_options: O, bincode_2_config: C) - where T: bincode::Encode + serde_incl::Serialize + core::fmt::Debug, - C: bincode::config::Config + Clone, - O: bincode1::Options + Clone -{ - let bincode_1_output = bincode_1_options.clone().serialize(t).unwrap(); - let bincode_2_output = bincode::encode_to_vec(t, bincode_2_config.clone()).unwrap(); - - assert_eq!(bincode_1_output, bincode_2_output, "{:?} serializes differently", t); -} -fn test_same(t: T) - where T: bincode::Encode + serde_incl::Serialize + core::fmt::Debug, -{ - test_same_with_config( - &t, - bincode1::options().with_big_endian().with_varint_encoding(), - bincode::config::Configuration::legacy().with_big_endian().with_variable_int_encoding() - ); - test_same_with_config( - &t, - bincode1::options().with_little_endian().with_varint_encoding(), - bincode::config::Configuration::legacy().with_little_endian().with_variable_int_encoding() - ); - test_same_with_config( - &t, - bincode1::options().with_big_endian().with_fixint_encoding(), - bincode::config::Configuration::legacy().with_big_endian().with_fixed_int_encoding() - ); - test_same_with_config( - &t, - bincode1::options().with_little_endian().with_fixint_encoding(), - bincode::config::Configuration::legacy().with_little_endian().with_fixed_int_encoding() - ); -} - -#[test] -fn rand() { - // https://github.com/rust-random/rand/blob/19404d68764ed08513131f82157e2ccad69dcf83/rand_pcg/src/pcg64.rs#L37-L40 - #[derive(Debug, bincode::Encode, bincode::Decode, serde_derive::Serialize, serde_derive::Deserialize)] - #[serde(crate = "serde_incl")] - pub struct Lcg64Xsh32 { - state: u64, - increment: u64, - } - - let mut rng = rand::thread_rng(); - for _ in 0..100 { - test_same(Lcg64Xsh32 { - state: rng.gen(), - increment: rng.gen(), - }); - } -}