diff --git a/derive/Cargo.toml b/derive/Cargo.toml index f573e24..cc43880 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.6" diff --git a/derive/src/attribute.rs b/derive/src/attribute.rs new file mode 100644 index 0000000..5f0b8ca --- /dev/null +++ b/derive/src/attribute.rs @@ -0,0 +1,74 @@ +use virtue::prelude::*; +use virtue::utils::{parse_tagged_attribute, ParsedAttribute}; + +pub struct ContainerAttributes { + pub crate_name: String, +} + +impl Default for ContainerAttributes { + fn default() -> Self { + Self { + crate_name: "::bincode".to_string(), + } + } +} + +impl FromAttribute for ContainerAttributes { + fn parse(group: &Group) -> Result> { + let attributes = match parse_tagged_attribute(group, "bincode")? { + Some(body) => body, + None => return Ok(None), + }; + let mut result = Self::default(); + for attribute in attributes { + match attribute { + ParsedAttribute::Property(key, val) if key.to_string() == "crate" => { + let val_string = val.to_string(); + if val_string.starts_with('"') && val_string.ends_with('"') { + result.crate_name = val_string[1..val_string.len() - 1].to_string(); + } else { + return Err(Error::custom_at("Should be a literal str", val.span())); + } + } + ParsedAttribute::Tag(i) => { + return Err(Error::custom_at("Unknown field attribute", i.span())) + } + ParsedAttribute::Property(key, _) => { + return Err(Error::custom_at("Unknown field attribute", key.span())) + } + _ => {} + } + } + Ok(Some(result)) + } +} + +#[derive(Default)] +pub struct FieldAttributes { + pub with_serde: bool, +} + +impl FromAttribute for FieldAttributes { + fn parse(group: &Group) -> Result> { + let attributes = match parse_tagged_attribute(group, "bincode")? { + Some(body) => body, + None => return Ok(None), + }; + let mut result = Self::default(); + for attribute in attributes { + match attribute { + ParsedAttribute::Tag(i) if i.to_string() == "with_serde" => { + result.with_serde = true; + } + ParsedAttribute::Tag(i) => { + return Err(Error::custom_at("Unknown field attribute", i.span())) + } + ParsedAttribute::Property(key, _) => { + return Err(Error::custom_at("Unknown field attribute", key.span())) + } + _ => {} + } + } + Ok(Some(result)) + } +} diff --git a/derive/src/derive_enum.rs b/derive/src/derive_enum.rs index 2b643a6..228600a 100644 --- a/derive/src/derive_enum.rs +++ b/derive/src/derive_enum.rs @@ -1,12 +1,11 @@ -use super::FieldAttribute; -use virtue::generate::{FnSelfArg, Generator, StreamBuilder}; -use virtue::parse::{EnumVariant, Fields}; +use crate::attribute::{ContainerAttributes, FieldAttributes}; use virtue::prelude::*; const TUPLE_FIELD_PREFIX: &str = "field_"; -pub struct DeriveEnum { +pub(crate) struct DeriveEnum { pub variants: Vec, + pub attributes: ContainerAttributes, } impl DeriveEnum { @@ -19,18 +18,24 @@ impl DeriveEnum { } pub fn generate_encode(self, generator: &mut Generator) -> Result<()> { + let crate_name = self.attributes.crate_name.as_str(); generator - .impl_for("bincode::Encode")? + .impl_for(format!("{}::Encode", crate_name))? .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, format!("{}::Encode", crate_name)) + .unwrap(); } }) .generate_fn("encode") - .with_generic("E", ["bincode::enc::Encoder"]) + .with_generic_deps("E", [format!("{}::enc::Encoder", crate_name)]) .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>", + crate_name + )) .body(|fn_body| { fn_body.ident_str("match"); fn_body.ident_str("self"); @@ -76,7 +81,7 @@ impl DeriveEnum { // } match_body.group(Delimiter::Brace, |body| { // variant index - body.push_parsed("::encode")?; + body.push_parsed(format!("::encode", crate_name))?; body.group(Delimiter::Parenthesis, |args| { args.punct('&'); args.group(Delimiter::Parenthesis, |num| { @@ -91,17 +96,22 @@ 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)? { + let attributes = field_name + .attributes() + .get_attribute::()? + .unwrap_or_default(); + if attributes.with_serde { body.push_parsed(format!( - "bincode::Encode::encode(&bincode::serde::Compat({}), encoder)?;", + "{0}::Encode::encode(&{0}::serde::Compat({1}), encoder)?;", + crate_name, field_name.to_string_with_prefix(TUPLE_FIELD_PREFIX), ))?; } else { body.push_parsed(format!( - "bincode::Encode::encode({}, encoder)?;", + "{0}::Encode::encode({1}, encoder)?;", + crate_name, field_name.to_string_with_prefix(TUPLE_FIELD_PREFIX), - )) - ?; + ))?; } } body.push_parsed("Ok(())")?; @@ -124,6 +134,8 @@ impl DeriveEnum { /// Build the catch-all case for an int-to-enum decode implementation fn invalid_variant_case(&self, enum_name: &str, result: &mut StreamBuilder) -> Result { + let crate_name = self.attributes.crate_name.as_str(); + // we'll be generating: // variant => Err( // bincode::error::DecodeError::UnexpectedVariant { @@ -142,7 +154,10 @@ 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(format!( + "{}::error::DecodeError::UnexpectedVariant", + crate_name + ))?; err_inner.group(Delimiter::Brace, |variant_inner| { variant_inner.ident_str("found"); variant_inner.punct(':'); @@ -159,7 +174,10 @@ 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(format!( + "{}::error::AllowedEnumVariants::Allowed", + crate_name + ))?; variant_inner.group(Delimiter::Parenthesis, |allowed_inner| { allowed_inner.punct('&'); allowed_inner.group(Delimiter::Bracket, |allowed_slice| { @@ -176,7 +194,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} }}", + crate_name, self.variants.len() - 1 ))?; } @@ -188,29 +207,35 @@ impl DeriveEnum { } pub fn generate_decode(&self, generator: &mut Generator) -> Result<()> { + let crate_name = self.attributes.crate_name.as_str(); + // Remember to keep this mostly in sync with generate_borrow_decode let enum_name = generator.target_name().to_string(); generator - .impl_for("bincode::Decode")? + .impl_for(format!("{}::Decode", crate_name))? .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, format!("{}::Decode", crate_name)).unwrap(); } }) .generate_fn("decode") - .with_generic("D", ["bincode::de::Decoder"]) + .with_generic_deps("D", [format!("{}::de::Decoder", crate_name)]) .with_arg("decoder", "&mut D") - .with_return_type("core::result::Result") + .with_return_type(format!("core::result::Result", crate_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 + ))?; } else { fn_builder - .push_parsed( - "let variant_index = ::decode(decoder)?;", - )?; + .push_parsed(format!( + "let variant_index = ::decode(decoder)?;", + crate_name + ))?; fn_builder.push_parsed("match variant_index")?; fn_builder.group(Delimiter::Brace, |variant_case| { for (mut variant_index, variant) in self.iter_fields() { @@ -240,12 +265,19 @@ impl DeriveEnum { variant_body.ident(field.unwrap_ident().clone()); } variant_body.punct(':'); - if field.attributes().has_attribute(FieldAttribute::WithSerde)? { + let attributes = field.attributes().get_attribute::()?.unwrap_or_default(); + if attributes.with_serde { variant_body - .push_parsed(" as bincode::Decode>::decode(decoder)?.0,")?; + .push_parsed(format!( + "<{0}::serde::Compat<_> as {0}::Decode>::decode(decoder)?.0,", + crate_name + ))?; } else { variant_body - .push_parsed("bincode::Decode::decode(decoder)?,")?; + .push_parsed(format!( + "{}::Decode::decode(decoder)?,", + crate_name + ))?; } } Ok(()) @@ -265,26 +297,30 @@ 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.attributes.crate_name.clone(); + // Remember to keep this mostly in sync with generate_decode let enum_name = generator.target_name().to_string(); - generator.impl_for_with_lifetimes("bincode::BorrowDecode", &["__de"])? + generator.impl_for_with_lifetimes(format!("{}::BorrowDecode", crate_name), ["__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, format!("{}::enc::BorrowDecode", crate_name)).unwrap(); } }) .generate_fn("borrow_decode") - .with_generic("D", ["bincode::de::BorrowDecoder<'__de>"]) + .with_generic_deps("D", [format!("{}::de::BorrowDecoder<'__de>", crate_name)]) .with_arg("decoder", "&mut D") - .with_return_type("core::result::Result") + .with_return_type(format!("core::result::Result", crate_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 + ))?; } else { fn_builder - .push_parsed("let variant_index = ::decode(decoder)?;")?; + .push_parsed(format!("let variant_index = ::decode(decoder)?;", crate_name))?; fn_builder.push_parsed("match variant_index")?; fn_builder.group(Delimiter::Brace, |variant_case| { for (mut variant_index, variant) in self.iter_fields() { @@ -314,11 +350,12 @@ impl DeriveEnum { variant_body.ident(field.unwrap_ident().clone()); } variant_body.punct(':'); - if field.attributes().has_attribute(FieldAttribute::WithSerde)? { + let attributes = field.attributes().get_attribute::()?.unwrap_or_default(); + if attributes.with_serde { 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))?; } else { - variant_body.push_parsed("bincode::BorrowDecode::borrow_decode(decoder)?,")?; + variant_body.push_parsed(format!("{}::BorrowDecode::borrow_decode(decoder)?,", crate_name))?; } } Ok(()) diff --git a/derive/src/derive_struct.rs b/derive/src/derive_struct.rs index 474afa7..5f55006 100644 --- a/derive/src/derive_struct.rs +++ b/derive/src/derive_struct.rs @@ -1,44 +1,50 @@ -use super::FieldAttribute; +use crate::attribute::{ContainerAttributes, FieldAttributes}; use virtue::generate::Generator; use virtue::parse::Fields; use virtue::prelude::*; -pub struct DeriveStruct { +pub(crate) struct DeriveStruct { pub fields: Fields, + pub attributes: ContainerAttributes, } impl DeriveStruct { pub fn generate_encode(self, generator: &mut Generator) -> Result<()> { - let DeriveStruct { fields } = self; + let DeriveStruct { fields, attributes } = self; + let crate_name = attributes.crate_name; generator - .impl_for("bincode::Encode")? + .impl_for(&format!("{}::Encode", crate_name))? .modify_generic_constraints(|generics, where_constraints| { for g in generics.iter_generics() { where_constraints - .push_constraint(g, "bincode::Encode") + .push_constraint(g, format!("{}::Encode", crate_name)) .unwrap(); } }) .generate_fn("encode") - .with_generic("E", ["bincode::enc::Encoder"]) + .with_generic_deps("E", [format!("{}::enc::Encoder", crate_name)]) .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 + )) .body(|fn_body| { for field in fields.names() { - if field + let attributes = field .attributes() - .has_attribute(FieldAttribute::WithSerde)? - { + .get_attribute::()? + .unwrap_or_default(); + if attributes.with_serde { 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, field ))?; } else { fn_body.push_parsed(format!( - "bincode::Encode::encode(&self.{}, encoder)?;", - field + "{}::Encode::encode(&self.{}, encoder)?;", + crate_name, field ))?; } } @@ -50,19 +56,20 @@ 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, attributes } = self; + let crate_name = attributes.crate_name; generator - .impl_for("bincode::Decode")? + .impl_for(format!("{}::Decode", crate_name))? .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, format!("{}::Decode", crate_name)).unwrap(); } }) .generate_fn("decode") - .with_generic("D", ["bincode::de::Decoder"]) + .with_generic_deps("D", [format!("{}::de::Decoder", crate_name)]) .with_arg("decoder", "&mut D") - .with_return_type("core::result::Result") + .with_return_type(format!("core::result::Result", crate_name)) .body(|fn_body| { // Ok(Self { fn_body.ident_str("Ok"); @@ -76,16 +83,19 @@ impl DeriveStruct { // ... // } for field in fields.names() { - if field.attributes().has_attribute(FieldAttribute::WithSerde)? { + let attributes = field.attributes().get_attribute::()?.unwrap_or_default(); + if attributes.with_serde { struct_body .push_parsed(format!( - "{}: ( as bincode::Decode>::decode(decoder)?).0,", + "{1}: (<{0}::serde::Compat<_> as {0}::Decode>::decode(decoder)?).0,", + crate_name, field ))?; } else { struct_body .push_parsed(format!( - "{}: bincode::Decode::decode(decoder)?,", + "{1}: {0}::Decode::decode(decoder)?,", + crate_name, field ))?; } @@ -101,19 +111,20 @@ 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, attributes } = self; + let crate_name = attributes.crate_name; generator - .impl_for_with_lifetimes("bincode::BorrowDecode", &["__de"])? + .impl_for_with_lifetimes(format!("{}::BorrowDecode", crate_name), ["__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, format!("{}::BorrowDecode", crate_name)).unwrap(); } }) .generate_fn("borrow_decode") - .with_generic("D", ["bincode::de::BorrowDecoder<'__de>"]) + .with_generic_deps("D", [format!("{}::de::BorrowDecoder<'__de>", crate_name)]) .with_arg("decoder", "&mut D") - .with_return_type("core::result::Result") + .with_return_type(format!("core::result::Result", crate_name)) .body(|fn_body| { // Ok(Self { fn_body.ident_str("Ok"); @@ -121,16 +132,19 @@ impl DeriveStruct { ok_group.ident_str("Self"); ok_group.group(Delimiter::Brace, |struct_body| { for field in fields.names() { - if field.attributes().has_attribute(FieldAttribute::WithSerde)? { + let attributes = field.attributes().get_attribute::()?.unwrap_or_default(); + if attributes.with_serde { 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, field ))?; } else { struct_body .push_parsed(format!( - "{}: bincode::BorrowDecode::borrow_decode(decoder)?,", + "{1}: {0}::BorrowDecode::borrow_decode(decoder)?,", + crate_name, field ))?; } @@ -139,7 +153,7 @@ impl DeriveStruct { })?; Ok(()) })?; - Ok(()) + Ok(()) })?; Ok(()) } diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 806dbd0..c4aec81 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -1,6 +1,8 @@ +mod attribute; mod derive_enum; mod derive_struct; +use attribute::ContainerAttributes; use virtue::prelude::*; #[proc_macro_derive(Encode, attributes(bincode))] @@ -10,27 +12,30 @@ 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 attributes = attributes + .get_attribute::()? + .unwrap_or_default(); match body { Body::Struct(body) => { derive_struct::DeriveStruct { fields: body.fields, + attributes, } .generate_encode(&mut generator)?; } Body::Enum(body) => { derive_enum::DeriveEnum { variants: body.variants, + attributes, } .generate_encode(&mut generator)?; } } - let name = generator.target_name().clone(); - let stream = generator.finish()?; - dump_output(name, "Encode", &stream); - Ok(stream) + generator.export_to_file("Encode"); + generator.finish() } #[proc_macro_derive(Decode, attributes(bincode))] @@ -40,93 +45,61 @@ 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 attributes = attributes + .get_attribute::()? + .unwrap_or_default(); match body { Body::Struct(body) => { derive_struct::DeriveStruct { fields: body.fields, + attributes, } .generate_decode(&mut generator)?; } Body::Enum(body) => { derive_enum::DeriveEnum { variants: body.variants, + attributes, } .generate_decode(&mut generator)?; } } - let name = generator.target_name().clone(); - let stream = generator.finish()?; - dump_output(name, "Decode", &stream); - Ok(stream) + generator.export_to_file("Decode"); + generator.finish() } #[proc_macro_derive(BorrowDecode, attributes(bincode))] -pub fn derive_brrow_decode(input: proc_macro::TokenStream) -> proc_macro::TokenStream { +pub fn derive_borrow_decode(input: proc_macro::TokenStream) -> proc_macro::TokenStream { derive_borrow_decode_inner(input).unwrap_or_else(|e| e.into_token_stream()) } 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 attributes = attributes + .get_attribute::()? + .unwrap_or_default(); match body { Body::Struct(body) => { derive_struct::DeriveStruct { fields: body.fields, + attributes, } .generate_borrow_decode(&mut generator)?; } Body::Enum(body) => { derive_enum::DeriveEnum { variants: body.variants, + attributes, } .generate_borrow_decode(&mut generator)?; } } - let name = generator.target_name().clone(); - let stream = generator.finish()?; - dump_output(name, "BorrowDecode", &stream); - Ok(stream) -} - -fn dump_output(name: Ident, derive: &str, stream: &TokenStream) { - use std::io::Write; - - 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()); - } - } - } -} - -#[derive(Debug, Copy, Clone, PartialEq)] -enum FieldAttribute { - WithSerde, -} - -impl FromAttribute for FieldAttribute { - fn parse(group: &Group) -> Result> { - let body = match virtue::utils::parse_tagged_attribute(group, "bincode") { - Some(body) => body, - None => return Ok(None), - }; - match body.into_iter().next() { - Some(TokenTree::Ident(ident)) if ident.to_string() == "with_serde" => { - Ok(Some(Self::WithSerde)) - } - token => Err(virtue::Error::custom_at_opt_token( - "Unknown attribute, expected one of: \"with_serde\"", - token, - )), - } - } + generator.export_to_file("BorrowDecode"); + generator.finish() } diff --git a/tests/derive_rename.rs b/tests/derive_rename.rs new file mode 100644 index 0000000..5b708da --- /dev/null +++ b/tests/derive_rename.rs @@ -0,0 +1,13 @@ +#![cfg(feature = "derive")] + +extern crate bincode as bincode_new; + +// Make sure that the `bincode` crate exists, just symlink it to `core. +extern crate core as bincode; + +#[derive(bincode_new::Encode)] +#[bincode(crate = "bincode_new")] +struct DeriveRenameTest { + a: u32, + b: u32, +}