Skip to content

Commit

Permalink
Updated to virtue 0.0.6, added #[bincode(crate = other)] attribute (#494
Browse files Browse the repository at this point in the history
)

* Updated to virtue 0.0.6, added #[bincode(crate = other)] attribute

* Simplified the ContainerAttributes and FieldAttributes
  • Loading branch information
VictorKoenders committed Jan 31, 2022
1 parent d54dcb8 commit 466cccb
Show file tree
Hide file tree
Showing 6 changed files with 235 additions and 124 deletions.
2 changes: 1 addition & 1 deletion derive/Cargo.toml
Expand Up @@ -16,4 +16,4 @@ description = "Implementation of #[derive(Encode, Decode)] for bincode"
proc-macro = true

[dependencies]
virtue = "0.0.4"
virtue = "0.0.6"
74 changes: 74 additions & 0 deletions 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<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))
}
}
113 changes: 75 additions & 38 deletions 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<EnumVariant>,
pub attributes: ContainerAttributes,
}

impl DeriveEnum {
Expand All @@ -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");
Expand Down Expand Up @@ -76,7 +81,7 @@ impl DeriveEnum {
// }
match_body.group(Delimiter::Brace, |body| {
// 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| {
args.punct('&');
args.group(Delimiter::Parenthesis, |num| {
Expand All @@ -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::<FieldAttributes>()?
.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(())")?;
Expand All @@ -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 {
Expand All @@ -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(':');
Expand All @@ -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| {
Expand All @@ -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
))?;
}
Expand All @@ -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<Self, bincode::error::DecodeError>")
.with_return_type(format!("core::result::Result<Self, {}::error::DecodeError>", 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::<Self>() })")?;
fn_builder.push_parsed(format!(
"core::result::Result::Err({}::error::DecodeError::EmptyEnum {{ type_name: core::any::type_name::<Self>() }})",
crate_name
))?;
} else {
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.group(Delimiter::Brace, |variant_case| {
for (mut variant_index, variant) in self.iter_fields() {
Expand Down Expand Up @@ -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::<FieldAttributes>()?.unwrap_or_default();
if attributes.with_serde {
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 {
variant_body
.push_parsed("bincode::Decode::decode(decoder)?,")?;
.push_parsed(format!(
"{}::Decode::decode(decoder)?,",
crate_name
))?;
}
}
Ok(())
Expand All @@ -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<Self, bincode::error::DecodeError>")
.with_return_type(format!("core::result::Result<Self, {}::error::DecodeError>", 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::<Self>() })")?;
fn_builder.push_parsed(format!(
"core::result::Result::Err({}::error::DecodeError::EmptyEnum {{ type_name: core::any::type_name::<Self>() }})",
crate_name
))?;
} else {
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.group(Delimiter::Brace, |variant_case| {
for (mut variant_index, variant) in self.iter_fields() {
Expand Down Expand Up @@ -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::<FieldAttributes>()?.unwrap_or_default();
if attributes.with_serde {
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 {
variant_body.push_parsed("bincode::BorrowDecode::borrow_decode(decoder)?,")?;
variant_body.push_parsed(format!("{}::BorrowDecode::borrow_decode(decoder)?,", crate_name))?;
}
}
Ok(())
Expand Down

0 comments on commit 466cccb

Please sign in to comment.