Updated to virtue 0.0.6, added #[bincode(crate = other)] attribute (#494)
* Updated to virtue 0.0.6, added #[bincode(crate = other)] attribute * Simplified the ContainerAttributes and FieldAttributes
This commit is contained in:
parent
d90f501872
commit
d4e7915c17
|
|
@ -16,4 +16,4 @@ description = "Implementation of #[derive(Encode, Decode)] for bincode"
|
||||||
proc-macro = true
|
proc-macro = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
virtue = "0.0.4"
|
virtue = "0.0.6"
|
||||||
|
|
|
||||||
|
|
@ -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<Option<Self>> {
|
||||||
|
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<Option<Self>> {
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
use super::FieldAttribute;
|
use crate::attribute::{ContainerAttributes, FieldAttributes};
|
||||||
use virtue::generate::{FnSelfArg, Generator, StreamBuilder};
|
|
||||||
use virtue::parse::{EnumVariant, Fields};
|
|
||||||
use virtue::prelude::*;
|
use virtue::prelude::*;
|
||||||
|
|
||||||
const TUPLE_FIELD_PREFIX: &str = "field_";
|
const TUPLE_FIELD_PREFIX: &str = "field_";
|
||||||
|
|
||||||
pub struct DeriveEnum {
|
pub(crate) struct DeriveEnum {
|
||||||
pub variants: Vec<EnumVariant>,
|
pub variants: Vec<EnumVariant>,
|
||||||
|
pub attributes: ContainerAttributes,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DeriveEnum {
|
impl DeriveEnum {
|
||||||
|
|
@ -19,18 +18,24 @@ impl DeriveEnum {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_encode(self, generator: &mut Generator) -> Result<()> {
|
pub fn generate_encode(self, generator: &mut Generator) -> Result<()> {
|
||||||
|
let crate_name = self.attributes.crate_name.as_str();
|
||||||
generator
|
generator
|
||||||
.impl_for("bincode::Encode")?
|
.impl_for(format!("{}::Encode", crate_name))?
|
||||||
.modify_generic_constraints(|generics, where_constraints| {
|
.modify_generic_constraints(|generics, where_constraints| {
|
||||||
for g in generics.iter_generics() {
|
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")
|
.generate_fn("encode")
|
||||||
.with_generic("E", ["bincode::enc::Encoder"])
|
.with_generic_deps("E", [format!("{}::enc::Encoder", crate_name)])
|
||||||
.with_self_arg(FnSelfArg::RefSelf)
|
.with_self_arg(FnSelfArg::RefSelf)
|
||||||
.with_arg("encoder", "&mut E")
|
.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| {
|
.body(|fn_body| {
|
||||||
fn_body.ident_str("match");
|
fn_body.ident_str("match");
|
||||||
fn_body.ident_str("self");
|
fn_body.ident_str("self");
|
||||||
|
|
@ -76,7 +81,7 @@ impl DeriveEnum {
|
||||||
// }
|
// }
|
||||||
match_body.group(Delimiter::Brace, |body| {
|
match_body.group(Delimiter::Brace, |body| {
|
||||||
// variant index
|
// variant index
|
||||||
body.push_parsed("<u32 as bincode::Encode>::encode")?;
|
body.push_parsed(format!("<u32 as {}::Encode>::encode", crate_name))?;
|
||||||
body.group(Delimiter::Parenthesis, |args| {
|
body.group(Delimiter::Parenthesis, |args| {
|
||||||
args.punct('&');
|
args.punct('&');
|
||||||
args.group(Delimiter::Parenthesis, |num| {
|
args.group(Delimiter::Parenthesis, |num| {
|
||||||
|
|
@ -91,17 +96,22 @@ impl DeriveEnum {
|
||||||
body.punct(';');
|
body.punct(';');
|
||||||
// If we have any fields, encode them all one by one
|
// If we have any fields, encode them all one by one
|
||||||
for field_name in variant.fields.names() {
|
for field_name in variant.fields.names() {
|
||||||
if field_name.attributes().has_attribute(FieldAttribute::WithSerde)? {
|
let attributes = field_name
|
||||||
|
.attributes()
|
||||||
|
.get_attribute::<FieldAttributes>()?
|
||||||
|
.unwrap_or_default();
|
||||||
|
if attributes.with_serde {
|
||||||
body.push_parsed(format!(
|
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),
|
field_name.to_string_with_prefix(TUPLE_FIELD_PREFIX),
|
||||||
))?;
|
))?;
|
||||||
} else {
|
} else {
|
||||||
body.push_parsed(format!(
|
body.push_parsed(format!(
|
||||||
"bincode::Encode::encode({}, encoder)?;",
|
"{0}::Encode::encode({1}, encoder)?;",
|
||||||
|
crate_name,
|
||||||
field_name.to_string_with_prefix(TUPLE_FIELD_PREFIX),
|
field_name.to_string_with_prefix(TUPLE_FIELD_PREFIX),
|
||||||
))
|
))?;
|
||||||
?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
body.push_parsed("Ok(())")?;
|
body.push_parsed("Ok(())")?;
|
||||||
|
|
@ -124,6 +134,8 @@ impl DeriveEnum {
|
||||||
|
|
||||||
/// Build the catch-all case for an int-to-enum decode implementation
|
/// Build the catch-all case for an int-to-enum decode implementation
|
||||||
fn invalid_variant_case(&self, enum_name: &str, result: &mut StreamBuilder) -> Result {
|
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:
|
// we'll be generating:
|
||||||
// variant => Err(
|
// variant => Err(
|
||||||
// bincode::error::DecodeError::UnexpectedVariant {
|
// bincode::error::DecodeError::UnexpectedVariant {
|
||||||
|
|
@ -142,7 +154,10 @@ impl DeriveEnum {
|
||||||
result.puncts("=>");
|
result.puncts("=>");
|
||||||
result.ident_str("Err");
|
result.ident_str("Err");
|
||||||
result.group(Delimiter::Parenthesis, |err_inner| {
|
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| {
|
err_inner.group(Delimiter::Brace, |variant_inner| {
|
||||||
variant_inner.ident_str("found");
|
variant_inner.ident_str("found");
|
||||||
variant_inner.punct(':');
|
variant_inner.punct(':');
|
||||||
|
|
@ -159,7 +174,10 @@ impl DeriveEnum {
|
||||||
|
|
||||||
if self.variants.iter().any(|i| i.has_fixed_value()) {
|
if self.variants.iter().any(|i| i.has_fixed_value()) {
|
||||||
// we have fixed values, implement AllowedEnumVariants::Allowed
|
// 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| {
|
variant_inner.group(Delimiter::Parenthesis, |allowed_inner| {
|
||||||
allowed_inner.punct('&');
|
allowed_inner.punct('&');
|
||||||
allowed_inner.group(Delimiter::Bracket, |allowed_slice| {
|
allowed_inner.group(Delimiter::Bracket, |allowed_slice| {
|
||||||
|
|
@ -176,7 +194,8 @@ impl DeriveEnum {
|
||||||
} else {
|
} else {
|
||||||
// no fixed values, implement a range
|
// no fixed values, implement a range
|
||||||
variant_inner.push_parsed(format!(
|
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
|
self.variants.len() - 1
|
||||||
))?;
|
))?;
|
||||||
}
|
}
|
||||||
|
|
@ -188,29 +207,35 @@ impl DeriveEnum {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_decode(&self, generator: &mut Generator) -> Result<()> {
|
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
|
// Remember to keep this mostly in sync with generate_borrow_decode
|
||||||
|
|
||||||
let enum_name = generator.target_name().to_string();
|
let enum_name = generator.target_name().to_string();
|
||||||
|
|
||||||
generator
|
generator
|
||||||
.impl_for("bincode::Decode")?
|
.impl_for(format!("{}::Decode", crate_name))?
|
||||||
.modify_generic_constraints(|generics, where_constraints| {
|
.modify_generic_constraints(|generics, where_constraints| {
|
||||||
for g in generics.iter_generics() {
|
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")
|
.generate_fn("decode")
|
||||||
.with_generic("D", ["bincode::de::Decoder"])
|
.with_generic_deps("D", [format!("{}::de::Decoder", crate_name)])
|
||||||
.with_arg("decoder", "&mut D")
|
.with_arg("decoder", "&mut D")
|
||||||
.with_return_type("core::result::Result<Self, bincode::error::DecodeError>")
|
.with_return_type(format!("core::result::Result<Self, {}::error::DecodeError>", crate_name))
|
||||||
.body(|fn_builder| {
|
.body(|fn_builder| {
|
||||||
if self.variants.is_empty() {
|
if self.variants.is_empty() {
|
||||||
fn_builder.push_parsed("core::result::Result::Err(bincode::error::DecodeError::EmptyEnum { type_name: core::any::type_name::<Self>() })")?;
|
fn_builder.push_parsed(format!(
|
||||||
|
"core::result::Result::Err({}::error::DecodeError::EmptyEnum {{ type_name: core::any::type_name::<Self>() }})",
|
||||||
|
crate_name
|
||||||
|
))?;
|
||||||
} else {
|
} else {
|
||||||
fn_builder
|
fn_builder
|
||||||
.push_parsed(
|
.push_parsed(format!(
|
||||||
"let variant_index = <u32 as bincode::Decode>::decode(decoder)?;",
|
"let variant_index = <u32 as {}::Decode>::decode(decoder)?;",
|
||||||
)?;
|
crate_name
|
||||||
|
))?;
|
||||||
fn_builder.push_parsed("match variant_index")?;
|
fn_builder.push_parsed("match variant_index")?;
|
||||||
fn_builder.group(Delimiter::Brace, |variant_case| {
|
fn_builder.group(Delimiter::Brace, |variant_case| {
|
||||||
for (mut variant_index, variant) in self.iter_fields() {
|
for (mut variant_index, variant) in self.iter_fields() {
|
||||||
|
|
@ -240,12 +265,19 @@ impl DeriveEnum {
|
||||||
variant_body.ident(field.unwrap_ident().clone());
|
variant_body.ident(field.unwrap_ident().clone());
|
||||||
}
|
}
|
||||||
variant_body.punct(':');
|
variant_body.punct(':');
|
||||||
if field.attributes().has_attribute(FieldAttribute::WithSerde)? {
|
let attributes = field.attributes().get_attribute::<FieldAttributes>()?.unwrap_or_default();
|
||||||
|
if attributes.with_serde {
|
||||||
variant_body
|
variant_body
|
||||||
.push_parsed("<bincode::serde::Compat<_> as bincode::Decode>::decode(decoder)?.0,")?;
|
.push_parsed(format!(
|
||||||
|
"<{0}::serde::Compat<_> as {0}::Decode>::decode(decoder)?.0,",
|
||||||
|
crate_name
|
||||||
|
))?;
|
||||||
} else {
|
} else {
|
||||||
variant_body
|
variant_body
|
||||||
.push_parsed("bincode::Decode::decode(decoder)?,")?;
|
.push_parsed(format!(
|
||||||
|
"{}::Decode::decode(decoder)?,",
|
||||||
|
crate_name
|
||||||
|
))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -265,26 +297,30 @@ impl DeriveEnum {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_borrow_decode(self, generator: &mut Generator) -> Result<()> {
|
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();
|
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| {
|
.modify_generic_constraints(|generics, where_constraints| {
|
||||||
for g in generics.iter_generics() {
|
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")
|
.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_arg("decoder", "&mut D")
|
||||||
.with_return_type("core::result::Result<Self, bincode::error::DecodeError>")
|
.with_return_type(format!("core::result::Result<Self, {}::error::DecodeError>", crate_name))
|
||||||
.body(|fn_builder| {
|
.body(|fn_builder| {
|
||||||
if self.variants.is_empty() {
|
if self.variants.is_empty() {
|
||||||
fn_builder.push_parsed("core::result::Result::Err(bincode::error::DecodeError::EmptyEnum { type_name: core::any::type_name::<Self>() })")?;
|
fn_builder.push_parsed(format!(
|
||||||
|
"core::result::Result::Err({}::error::DecodeError::EmptyEnum {{ type_name: core::any::type_name::<Self>() }})",
|
||||||
|
crate_name
|
||||||
|
))?;
|
||||||
} else {
|
} else {
|
||||||
fn_builder
|
fn_builder
|
||||||
.push_parsed("let variant_index = <u32 as bincode::Decode>::decode(decoder)?;")?;
|
.push_parsed(format!("let variant_index = <u32 as {}::Decode>::decode(decoder)?;", crate_name))?;
|
||||||
fn_builder.push_parsed("match variant_index")?;
|
fn_builder.push_parsed("match variant_index")?;
|
||||||
fn_builder.group(Delimiter::Brace, |variant_case| {
|
fn_builder.group(Delimiter::Brace, |variant_case| {
|
||||||
for (mut variant_index, variant) in self.iter_fields() {
|
for (mut variant_index, variant) in self.iter_fields() {
|
||||||
|
|
@ -314,11 +350,12 @@ impl DeriveEnum {
|
||||||
variant_body.ident(field.unwrap_ident().clone());
|
variant_body.ident(field.unwrap_ident().clone());
|
||||||
}
|
}
|
||||||
variant_body.punct(':');
|
variant_body.punct(':');
|
||||||
if field.attributes().has_attribute(FieldAttribute::WithSerde)? {
|
let attributes = field.attributes().get_attribute::<FieldAttributes>()?.unwrap_or_default();
|
||||||
|
if attributes.with_serde {
|
||||||
variant_body
|
variant_body
|
||||||
.push_parsed("<bincode::serde::BorrowCompat<_> as bincode::BorrowDecode>::borrow_decode(decoder)?.0,")?;
|
.push_parsed(format!("<{0}::serde::BorrowCompat<_> as {0}::BorrowDecode>::borrow_decode(decoder)?.0,", crate_name))?;
|
||||||
} else {
|
} else {
|
||||||
variant_body.push_parsed("bincode::BorrowDecode::borrow_decode(decoder)?,")?;
|
variant_body.push_parsed(format!("{}::BorrowDecode::borrow_decode(decoder)?,", crate_name))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -1,44 +1,50 @@
|
||||||
use super::FieldAttribute;
|
use crate::attribute::{ContainerAttributes, FieldAttributes};
|
||||||
use virtue::generate::Generator;
|
use virtue::generate::Generator;
|
||||||
use virtue::parse::Fields;
|
use virtue::parse::Fields;
|
||||||
use virtue::prelude::*;
|
use virtue::prelude::*;
|
||||||
|
|
||||||
pub struct DeriveStruct {
|
pub(crate) struct DeriveStruct {
|
||||||
pub fields: Fields,
|
pub fields: Fields,
|
||||||
|
pub attributes: ContainerAttributes,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DeriveStruct {
|
impl DeriveStruct {
|
||||||
pub fn generate_encode(self, generator: &mut Generator) -> Result<()> {
|
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
|
generator
|
||||||
.impl_for("bincode::Encode")?
|
.impl_for(&format!("{}::Encode", crate_name))?
|
||||||
.modify_generic_constraints(|generics, where_constraints| {
|
.modify_generic_constraints(|generics, where_constraints| {
|
||||||
for g in generics.iter_generics() {
|
for g in generics.iter_generics() {
|
||||||
where_constraints
|
where_constraints
|
||||||
.push_constraint(g, "bincode::Encode")
|
.push_constraint(g, format!("{}::Encode", crate_name))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.generate_fn("encode")
|
.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_self_arg(virtue::generate::FnSelfArg::RefSelf)
|
||||||
.with_arg("encoder", "&mut E")
|
.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| {
|
.body(|fn_body| {
|
||||||
for field in fields.names() {
|
for field in fields.names() {
|
||||||
if field
|
let attributes = field
|
||||||
.attributes()
|
.attributes()
|
||||||
.has_attribute(FieldAttribute::WithSerde)?
|
.get_attribute::<FieldAttributes>()?
|
||||||
{
|
.unwrap_or_default();
|
||||||
|
if attributes.with_serde {
|
||||||
fn_body.push_parsed(format!(
|
fn_body.push_parsed(format!(
|
||||||
"bincode::Encode::encode(&bincode::serde::Compat(&self.{}), encoder)?;",
|
"{0}::Encode::encode(&{0}::serde::Compat(&self.{1}), encoder)?;",
|
||||||
field
|
crate_name, field
|
||||||
))?;
|
))?;
|
||||||
} else {
|
} else {
|
||||||
fn_body.push_parsed(format!(
|
fn_body.push_parsed(format!(
|
||||||
"bincode::Encode::encode(&self.{}, encoder)?;",
|
"{}::Encode::encode(&self.{}, encoder)?;",
|
||||||
field
|
crate_name, field
|
||||||
))?;
|
))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -50,19 +56,20 @@ impl DeriveStruct {
|
||||||
|
|
||||||
pub fn generate_decode(self, generator: &mut Generator) -> Result<()> {
|
pub fn generate_decode(self, generator: &mut Generator) -> Result<()> {
|
||||||
// Remember to keep this mostly in sync with generate_borrow_decode
|
// 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
|
generator
|
||||||
.impl_for("bincode::Decode")?
|
.impl_for(format!("{}::Decode", crate_name))?
|
||||||
.modify_generic_constraints(|generics, where_constraints| {
|
.modify_generic_constraints(|generics, where_constraints| {
|
||||||
for g in generics.iter_generics() {
|
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")
|
.generate_fn("decode")
|
||||||
.with_generic("D", ["bincode::de::Decoder"])
|
.with_generic_deps("D", [format!("{}::de::Decoder", crate_name)])
|
||||||
.with_arg("decoder", "&mut D")
|
.with_arg("decoder", "&mut D")
|
||||||
.with_return_type("core::result::Result<Self, bincode::error::DecodeError>")
|
.with_return_type(format!("core::result::Result<Self, {}::error::DecodeError>", crate_name))
|
||||||
.body(|fn_body| {
|
.body(|fn_body| {
|
||||||
// Ok(Self {
|
// Ok(Self {
|
||||||
fn_body.ident_str("Ok");
|
fn_body.ident_str("Ok");
|
||||||
|
|
@ -76,16 +83,19 @@ impl DeriveStruct {
|
||||||
// ...
|
// ...
|
||||||
// }
|
// }
|
||||||
for field in fields.names() {
|
for field in fields.names() {
|
||||||
if field.attributes().has_attribute(FieldAttribute::WithSerde)? {
|
let attributes = field.attributes().get_attribute::<FieldAttributes>()?.unwrap_or_default();
|
||||||
|
if attributes.with_serde {
|
||||||
struct_body
|
struct_body
|
||||||
.push_parsed(format!(
|
.push_parsed(format!(
|
||||||
"{}: (<bincode::serde::Compat<_> as bincode::Decode>::decode(decoder)?).0,",
|
"{1}: (<{0}::serde::Compat<_> as {0}::Decode>::decode(decoder)?).0,",
|
||||||
|
crate_name,
|
||||||
field
|
field
|
||||||
))?;
|
))?;
|
||||||
} else {
|
} else {
|
||||||
struct_body
|
struct_body
|
||||||
.push_parsed(format!(
|
.push_parsed(format!(
|
||||||
"{}: bincode::Decode::decode(decoder)?,",
|
"{1}: {0}::Decode::decode(decoder)?,",
|
||||||
|
crate_name,
|
||||||
field
|
field
|
||||||
))?;
|
))?;
|
||||||
}
|
}
|
||||||
|
|
@ -101,19 +111,20 @@ impl DeriveStruct {
|
||||||
|
|
||||||
pub fn generate_borrow_decode(self, generator: &mut Generator) -> Result<()> {
|
pub fn generate_borrow_decode(self, generator: &mut Generator) -> Result<()> {
|
||||||
// Remember to keep this mostly in sync with generate_decode
|
// 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
|
generator
|
||||||
.impl_for_with_lifetimes("bincode::BorrowDecode", &["__de"])?
|
.impl_for_with_lifetimes(format!("{}::BorrowDecode", crate_name), ["__de"])?
|
||||||
.modify_generic_constraints(|generics, where_constraints| {
|
.modify_generic_constraints(|generics, where_constraints| {
|
||||||
for g in generics.iter_generics() {
|
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")
|
.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_arg("decoder", "&mut D")
|
||||||
.with_return_type("core::result::Result<Self, bincode::error::DecodeError>")
|
.with_return_type(format!("core::result::Result<Self, {}::error::DecodeError>", crate_name))
|
||||||
.body(|fn_body| {
|
.body(|fn_body| {
|
||||||
// Ok(Self {
|
// Ok(Self {
|
||||||
fn_body.ident_str("Ok");
|
fn_body.ident_str("Ok");
|
||||||
|
|
@ -121,16 +132,19 @@ impl DeriveStruct {
|
||||||
ok_group.ident_str("Self");
|
ok_group.ident_str("Self");
|
||||||
ok_group.group(Delimiter::Brace, |struct_body| {
|
ok_group.group(Delimiter::Brace, |struct_body| {
|
||||||
for field in fields.names() {
|
for field in fields.names() {
|
||||||
if field.attributes().has_attribute(FieldAttribute::WithSerde)? {
|
let attributes = field.attributes().get_attribute::<FieldAttributes>()?.unwrap_or_default();
|
||||||
|
if attributes.with_serde {
|
||||||
struct_body
|
struct_body
|
||||||
.push_parsed(format!(
|
.push_parsed(format!(
|
||||||
"{}: (<bincode::serde::BorrowCompat<_> as bincode::BorrowDecode>::borrow_decode(decoder)?).0,",
|
"{1}: (<{0}::serde::BorrowCompat<_> as {0}::BorrowDecode>::borrow_decode(decoder)?).0,",
|
||||||
|
crate_name,
|
||||||
field
|
field
|
||||||
))?;
|
))?;
|
||||||
} else {
|
} else {
|
||||||
struct_body
|
struct_body
|
||||||
.push_parsed(format!(
|
.push_parsed(format!(
|
||||||
"{}: bincode::BorrowDecode::borrow_decode(decoder)?,",
|
"{1}: {0}::BorrowDecode::borrow_decode(decoder)?,",
|
||||||
|
crate_name,
|
||||||
field
|
field
|
||||||
))?;
|
))?;
|
||||||
}
|
}
|
||||||
|
|
@ -139,7 +153,7 @@ impl DeriveStruct {
|
||||||
})?;
|
})?;
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
|
mod attribute;
|
||||||
mod derive_enum;
|
mod derive_enum;
|
||||||
mod derive_struct;
|
mod derive_struct;
|
||||||
|
|
||||||
|
use attribute::ContainerAttributes;
|
||||||
use virtue::prelude::*;
|
use virtue::prelude::*;
|
||||||
|
|
||||||
#[proc_macro_derive(Encode, attributes(bincode))]
|
#[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<TokenStream> {
|
fn derive_encode_inner(input: TokenStream) -> Result<TokenStream> {
|
||||||
let parse = Parse::new(input)?;
|
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::<ContainerAttributes>()?
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
match body {
|
match body {
|
||||||
Body::Struct(body) => {
|
Body::Struct(body) => {
|
||||||
derive_struct::DeriveStruct {
|
derive_struct::DeriveStruct {
|
||||||
fields: body.fields,
|
fields: body.fields,
|
||||||
|
attributes,
|
||||||
}
|
}
|
||||||
.generate_encode(&mut generator)?;
|
.generate_encode(&mut generator)?;
|
||||||
}
|
}
|
||||||
Body::Enum(body) => {
|
Body::Enum(body) => {
|
||||||
derive_enum::DeriveEnum {
|
derive_enum::DeriveEnum {
|
||||||
variants: body.variants,
|
variants: body.variants,
|
||||||
|
attributes,
|
||||||
}
|
}
|
||||||
.generate_encode(&mut generator)?;
|
.generate_encode(&mut generator)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = generator.target_name().clone();
|
generator.export_to_file("Encode");
|
||||||
let stream = generator.finish()?;
|
generator.finish()
|
||||||
dump_output(name, "Encode", &stream);
|
|
||||||
Ok(stream)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(Decode, attributes(bincode))]
|
#[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<TokenStream> {
|
fn derive_decode_inner(input: TokenStream) -> Result<TokenStream> {
|
||||||
let parse = Parse::new(input)?;
|
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::<ContainerAttributes>()?
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
match body {
|
match body {
|
||||||
Body::Struct(body) => {
|
Body::Struct(body) => {
|
||||||
derive_struct::DeriveStruct {
|
derive_struct::DeriveStruct {
|
||||||
fields: body.fields,
|
fields: body.fields,
|
||||||
|
attributes,
|
||||||
}
|
}
|
||||||
.generate_decode(&mut generator)?;
|
.generate_decode(&mut generator)?;
|
||||||
}
|
}
|
||||||
Body::Enum(body) => {
|
Body::Enum(body) => {
|
||||||
derive_enum::DeriveEnum {
|
derive_enum::DeriveEnum {
|
||||||
variants: body.variants,
|
variants: body.variants,
|
||||||
|
attributes,
|
||||||
}
|
}
|
||||||
.generate_decode(&mut generator)?;
|
.generate_decode(&mut generator)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = generator.target_name().clone();
|
generator.export_to_file("Decode");
|
||||||
let stream = generator.finish()?;
|
generator.finish()
|
||||||
dump_output(name, "Decode", &stream);
|
|
||||||
Ok(stream)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(BorrowDecode, attributes(bincode))]
|
#[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())
|
derive_borrow_decode_inner(input).unwrap_or_else(|e| e.into_token_stream())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn derive_borrow_decode_inner(input: TokenStream) -> Result<TokenStream> {
|
fn derive_borrow_decode_inner(input: TokenStream) -> Result<TokenStream> {
|
||||||
let parse = Parse::new(input)?;
|
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::<ContainerAttributes>()?
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
match body {
|
match body {
|
||||||
Body::Struct(body) => {
|
Body::Struct(body) => {
|
||||||
derive_struct::DeriveStruct {
|
derive_struct::DeriveStruct {
|
||||||
fields: body.fields,
|
fields: body.fields,
|
||||||
|
attributes,
|
||||||
}
|
}
|
||||||
.generate_borrow_decode(&mut generator)?;
|
.generate_borrow_decode(&mut generator)?;
|
||||||
}
|
}
|
||||||
Body::Enum(body) => {
|
Body::Enum(body) => {
|
||||||
derive_enum::DeriveEnum {
|
derive_enum::DeriveEnum {
|
||||||
variants: body.variants,
|
variants: body.variants,
|
||||||
|
attributes,
|
||||||
}
|
}
|
||||||
.generate_borrow_decode(&mut generator)?;
|
.generate_borrow_decode(&mut generator)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = generator.target_name().clone();
|
generator.export_to_file("BorrowDecode");
|
||||||
let stream = generator.finish()?;
|
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<Option<Self>> {
|
|
||||||
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,
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue