diff --git a/derive/Cargo.toml b/derive/Cargo.toml index be9b5663..eee094c2 100644 --- a/derive/Cargo.toml +++ b/derive/Cargo.toml @@ -19,4 +19,4 @@ description = "Implementation of #[derive(Encode, Decode)] for bincode" proc-macro = true [dependencies] -virtue = "0.0.11" +virtue = "0.0.13" diff --git a/derive/src/derive_enum.rs b/derive/src/derive_enum.rs index 614453a9..1ba34845 100644 --- a/derive/src/derive_enum.rs +++ b/derive/src/derive_enum.rs @@ -60,11 +60,10 @@ impl DeriveEnum { // if we have any fields, declare them here // Self::Variant { a, b, c } - if let Some(delimiter) = variant.fields.delimiter() { + if let Some(fields) = variant.fields.as_ref() { + let delimiter = fields.delimiter(); match_body.group(delimiter, |field_body| { - for (idx, field_name) in - variant.fields.names().into_iter().enumerate() - { + for (idx, field_name) in fields.names().into_iter().enumerate() { if idx != 0 { field_body.punct(','); } @@ -104,23 +103,25 @@ impl DeriveEnum { body.punct('?'); body.punct(';'); // If we have any fields, encode them all one by one - for field_name in variant.fields.names() { - let attributes = field_name - .attributes() - .get_attribute::()? - .unwrap_or_default(); - if attributes.with_serde { - body.push_parsed(format!( + if let Some(fields) = variant.fields.as_ref() { + for field_name in fields.names() { + let attributes = field_name + .attributes() + .get_attribute::()? + .unwrap_or_default(); + if attributes.with_serde { + body.push_parsed(format!( "{0}::Encode::encode(&{0}::serde::Compat({1}), encoder)?;", crate_name, field_name.to_string_with_prefix(TUPLE_FIELD_PREFIX), ))?; - } else { - body.push_parsed(format!( - "{0}::Encode::encode({1}, encoder)?;", - crate_name, - field_name.to_string_with_prefix(TUPLE_FIELD_PREFIX), - ))?; + } else { + body.push_parsed(format!( + "{0}::Encode::encode({1}, encoder)?;", + crate_name, + field_name.to_string_with_prefix(TUPLE_FIELD_PREFIX), + ))?; + } } } body.push_parsed("Ok(())")?; @@ -181,7 +182,7 @@ impl DeriveEnum { variant_inner.ident_str("allowed"); variant_inner.punct(':'); - if self.variants.iter().any(|i| i.has_fixed_value()) { + if self.variants.iter().any(|i| i.value.is_some()) { // we have fixed values, implement AllowedEnumVariants::Allowed variant_inner.push_parsed(format!( "&{}::error::AllowedEnumVariants::Allowed", @@ -230,7 +231,7 @@ impl DeriveEnum { where_constraints.push_parsed_constraint(bounds).map_err(|e| e.with_span(lit.span()))?; } else { for g in generics.iter_generics() { - where_constraints.push_constraint(g, format!("{}::Decode", crate_name)).unwrap(); + where_constraints.push_constraint(g, format!("{}::Decode", crate_name))?; } } Ok(()) @@ -272,27 +273,29 @@ impl DeriveEnum { variant_case_body.ident(variant.name.clone()); variant_case_body.group(Delimiter::Brace, |variant_body| { - let is_tuple = matches!(variant.fields, Fields::Tuple(_)); - for (idx, field) in variant.fields.names().into_iter().enumerate() { - if is_tuple { - variant_body.lit_usize(idx); - } else { - variant_body.ident(field.unwrap_ident().clone()); - } - variant_body.punct(':'); - let attributes = field.attributes().get_attribute::()?.unwrap_or_default(); - if attributes.with_serde { - variant_body - .push_parsed(format!( - "<{0}::serde::Compat<_> as {0}::Decode>::decode(decoder)?.0,", - crate_name - ))?; - } else { - variant_body - .push_parsed(format!( - "{}::Decode::decode(decoder)?,", - crate_name - ))?; + if let Some(fields) = variant.fields.as_ref() { + let is_tuple = matches!(fields, Fields::Tuple(_)); + for (idx, field) in fields.names().into_iter().enumerate() { + if is_tuple { + variant_body.lit_usize(idx); + } else { + variant_body.ident(field.unwrap_ident().clone()); + } + variant_body.punct(':'); + let attributes = field.attributes().get_attribute::()?.unwrap_or_default(); + if attributes.with_serde { + variant_body + .push_parsed(format!( + "<{0}::serde::Compat<_> as {0}::Decode>::decode(decoder)?.0,", + crate_name + ))?; + } else { + variant_body + .push_parsed(format!( + "{}::Decode::decode(decoder)?,", + crate_name + ))?; + } } } Ok(()) @@ -327,6 +330,9 @@ impl DeriveEnum { for g in generics.iter_generics() { where_constraints.push_constraint(g, format!("{}::de::BorrowDecode<'__de>", crate_name)).unwrap(); } + for lt in generics.iter_lifetimes() { + where_constraints.push_parsed_constraint(format!("'__de: '{}", lt.ident))?; + } } Ok(()) })? @@ -364,20 +370,22 @@ impl DeriveEnum { variant_case_body.ident(variant.name.clone()); variant_case_body.group(Delimiter::Brace, |variant_body| { - let is_tuple = matches!(variant.fields, Fields::Tuple(_)); - for (idx, field) in variant.fields.names().into_iter().enumerate() { - if is_tuple { - variant_body.lit_usize(idx); - } else { - variant_body.ident(field.unwrap_ident().clone()); - } - variant_body.punct(':'); - let attributes = field.attributes().get_attribute::()?.unwrap_or_default(); - if attributes.with_serde { - variant_body - .push_parsed(format!("<{0}::serde::BorrowCompat<_> as {0}::BorrowDecode>::borrow_decode(decoder)?.0,", crate_name))?; - } else { - variant_body.push_parsed(format!("{}::BorrowDecode::borrow_decode(decoder)?,", crate_name))?; + if let Some(fields) = variant.fields.as_ref() { + let is_tuple = matches!(fields, Fields::Tuple(_)); + for (idx, field) in fields.names().into_iter().enumerate() { + if is_tuple { + variant_body.lit_usize(idx); + } else { + variant_body.ident(field.unwrap_ident().clone()); + } + variant_body.punct(':'); + let attributes = field.attributes().get_attribute::()?.unwrap_or_default(); + if attributes.with_serde { + variant_body + .push_parsed(format!("<{0}::serde::BorrowCompat<_> as {0}::BorrowDecode>::borrow_decode(decoder)?.0,", crate_name))?; + } else { + 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 1b50cf8e..e948c85a 100644 --- a/derive/src/derive_struct.rs +++ b/derive/src/derive_struct.rs @@ -4,7 +4,7 @@ use virtue::parse::Fields; use virtue::prelude::*; pub(crate) struct DeriveStruct { - pub fields: Fields, + pub fields: Option, pub attributes: ContainerAttributes, } @@ -39,21 +39,23 @@ impl DeriveStruct { crate_name )) .body(|fn_body| { - for field in self.fields.names() { - let attributes = field - .attributes() - .get_attribute::()? - .unwrap_or_default(); - if attributes.with_serde { - fn_body.push_parsed(format!( - "{0}::Encode::encode(&{0}::serde::Compat(&self.{1}), encoder)?;", - crate_name, field - ))?; - } else { - fn_body.push_parsed(format!( - "{}::Encode::encode(&self.{}, encoder)?;", - crate_name, field - ))?; + if let Some(fields) = self.fields.as_ref() { + for field in fields.names() { + let attributes = field + .attributes() + .get_attribute::()? + .unwrap_or_default(); + if attributes.with_serde { + fn_body.push_parsed(format!( + "{0}::Encode::encode(&{0}::serde::Compat(&self.{1}), encoder)?;", + crate_name, field + ))?; + } else { + fn_body.push_parsed(format!( + "{}::Encode::encode(&self.{}, encoder)?;", + crate_name, field + ))?; + } } } fn_body.push_parsed("Ok(())")?; @@ -95,22 +97,24 @@ impl DeriveStruct { // b: bincode::Decode::decode(decoder)?, // ... // } - for field in &self.fields.names() { - let attributes = field.attributes().get_attribute::()?.unwrap_or_default(); - if attributes.with_serde { - struct_body - .push_parsed(format!( - "{1}: (<{0}::serde::Compat<_> as {0}::Decode>::decode(decoder)?).0,", - crate_name, - field - ))?; - } else { - struct_body - .push_parsed(format!( - "{1}: {0}::Decode::decode(decoder)?,", - crate_name, - field - ))?; + if let Some(fields) = self.fields.as_ref() { + for field in fields.names() { + let attributes = field.attributes().get_attribute::()?.unwrap_or_default(); + if attributes.with_serde { + struct_body + .push_parsed(format!( + "{1}: (<{0}::serde::Compat<_> as {0}::Decode>::decode(decoder)?).0,", + crate_name, + field + ))?; + } else { + struct_body + .push_parsed(format!( + "{1}: {0}::Decode::decode(decoder)?,", + crate_name, + field + ))?; + } } } Ok(()) @@ -137,6 +141,9 @@ impl DeriveStruct { for g in generics.iter_generics() { where_constraints.push_constraint(g, format!("{}::de::BorrowDecode<'__de>", crate_name)).unwrap(); } + for lt in generics.iter_lifetimes() { + where_constraints.push_parsed_constraint(format!("'__de: '{}", lt.ident))?; + } } Ok(()) })? @@ -150,22 +157,24 @@ impl DeriveStruct { fn_body.group(Delimiter::Parenthesis, |ok_group| { ok_group.ident_str("Self"); ok_group.group(Delimiter::Brace, |struct_body| { - for field in self.fields.names() { - let attributes = field.attributes().get_attribute::()?.unwrap_or_default(); - if attributes.with_serde { - struct_body - .push_parsed(format!( - "{1}: (<{0}::serde::BorrowCompat<_> as {0}::BorrowDecode>::borrow_decode(decoder)?).0,", - crate_name, - field - ))?; - } else { - struct_body - .push_parsed(format!( - "{1}: {0}::BorrowDecode::borrow_decode(decoder)?,", - crate_name, - field - ))?; + if let Some(fields) = self.fields.as_ref() { + for field in fields.names() { + let attributes = field.attributes().get_attribute::()?.unwrap_or_default(); + if attributes.with_serde { + struct_body + .push_parsed(format!( + "{1}: (<{0}::serde::BorrowCompat<_> as {0}::BorrowDecode>::borrow_decode(decoder)?).0,", + crate_name, + field + ))?; + } else { + struct_body + .push_parsed(format!( + "{1}: {0}::BorrowDecode::borrow_decode(decoder)?,", + crate_name, + field + ))?; + } } } Ok(()) diff --git a/tests/issues.rs b/tests/issues.rs index 39b04312..cd027b1d 100644 --- a/tests/issues.rs +++ b/tests/issues.rs @@ -35,3 +35,6 @@ mod issue_570; #[path = "issues/issue_592.rs"] mod issue_592; + +#[path = "issues/issue_614.rs"] +mod issue_614; diff --git a/tests/issues/issue_431.rs b/tests/issues/issue_431.rs index 7b9520d6..40c3c6a7 100644 --- a/tests/issues/issue_431.rs +++ b/tests/issues/issue_431.rs @@ -7,13 +7,15 @@ use std::borrow::Cow; use std::string::String; #[derive(Decode, Encode, PartialEq, Debug)] -#[bincode(borrow_decode_bounds = "&'__de U<'a, A>: ::bincode::de::BorrowDecode<'__de> + '__de")] +#[bincode( + borrow_decode_bounds = "&'__de U<'a, A>: ::bincode::de::BorrowDecode<'__de> + '__de, '__de: 'a" +)] struct T<'a, A: Clone + Encode + Decode> { t: Cow<'a, U<'a, A>>, } #[derive(Clone, Decode, Encode, PartialEq, Debug)] -#[bincode(borrow_decode_bounds = "&'__de A: ::bincode::de::BorrowDecode<'__de> + '__de")] +#[bincode(borrow_decode_bounds = "&'__de A: ::bincode::de::BorrowDecode<'__de> + '__de, '__de: 'a")] struct U<'a, A: Clone + Encode + Decode> { u: Cow<'a, A>, } diff --git a/tests/issues/issue_614.rs b/tests/issues/issue_614.rs new file mode 100644 index 00000000..b82c50ac --- /dev/null +++ b/tests/issues/issue_614.rs @@ -0,0 +1,22 @@ +#![cfg(feature = "derive")] + +use bincode::{Decode, Encode}; + +#[derive(Encode, Decode, Clone)] +pub struct A; +#[derive(Encode, Decode, Clone)] +pub struct B +where + T: Clone + Encode + Decode, +{ + pub t: T, +} + +#[derive(Encode, Decode)] +pub struct MyStruct +where + T: Clone + Encode + Decode, +{ + pub a: A, + pub b: B, +}