Skip to content

Commit

Permalink
Add basic struct flattening support (#16)
Browse files Browse the repository at this point in the history
This adds basic support for the `flatten` attribute when deriving structs.
  • Loading branch information
mitsuhiko authored Feb 11, 2022
1 parent 66ae3b6 commit 78a2e7a
Show file tree
Hide file tree
Showing 15 changed files with 692 additions and 113 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ All notable changes to deser are documented here.
directly on the `Sink`.
- The serializer state and deserializer state is now passed to `next_key`/
`next_value` and `next` on the sinks and emitters.
- Added support for `#[deser(flatten)]`.

## 0.5.0

Expand Down
22 changes: 22 additions & 0 deletions deser-derive/src/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ pub struct FieldAttrs<'a> {
rename: Option<String>,
aliases: Vec<String>,
default: Option<TypeDefault>,
flatten: bool,
skip_serializing_if: Option<syn::ExprPath>,
}

Expand All @@ -280,6 +281,7 @@ impl<'a> FieldAttrs<'a> {
rename: None,
aliases: Vec::new(),
default: None,
flatten: false,
skip_serializing_if: None,
};

Expand Down Expand Up @@ -318,6 +320,15 @@ impl<'a> FieldAttrs<'a> {
"default", &nv.lit,
)?));
}
syn::Meta::Path(path) if path.is_ident("flatten") => {
if rv.flatten {
return Err(syn::Error::new_spanned(
meta,
"duplicate flatten attribute",
));
}
rv.flatten = true;
}
syn::Meta::NameValue(nv) if nv.path.is_ident("skip_serializing_if") => {
if rv.skip_serializing_if.is_some() {
return Err(syn::Error::new_spanned(
Expand All @@ -335,6 +346,13 @@ impl<'a> FieldAttrs<'a> {
}
}

if rv.flatten && rv.default.is_some() {
return Err(syn::Error::new_spanned(
field,
"cannot combine flatten and default",
));
}

Ok(rv)
}

Expand All @@ -357,6 +375,10 @@ impl<'a> FieldAttrs<'a> {
self.default.as_ref()
}

pub fn flatten(&self) -> bool {
self.flatten
}

pub fn skip_serializing_if(&self) -> Option<&syn::ExprPath> {
self.skip_serializing_if.as_ref()
}
Expand Down
121 changes: 99 additions & 22 deletions deser-derive/src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,49 +27,79 @@ fn derive_struct(input: &syn::DeriveInput, fields: &syn::FieldsNamed) -> syn::Re

let container_attrs = ContainerAttrs::of(input)?;
let type_name = container_attrs.container_name();
let fieldname = &fields.named.iter().map(|f| &f.ident).collect::<Vec<_>>();
let fieldty = fields.named.iter().map(|f| &f.ty);
let sink_fieldname = &fields
let attrs = fields
.named
.iter()
.map(|f| {
.map(FieldAttrs::of)
.collect::<syn::Result<Vec<_>>>()?;
let fieldname = attrs.iter().map(|x| &x.field().ident).collect::<Vec<_>>();
let sink_fieldname = attrs
.iter()
.map(|x| {
syn::Ident::new(
&format!("field_{}", f.ident.as_ref().unwrap()),
&format!("field_{}", x.field().ident.as_ref().unwrap()),
Span::call_site(),
)
})
.collect::<Vec<_>>();
let attrs = fields
.named
let sink_fieldty = attrs
.iter()
.map(FieldAttrs::of)
.collect::<syn::Result<Vec<_>>>()?;
.map(|f| {
let ty = &f.field().ty;
if f.flatten() {
quote! {
::deser::de::OwnedSink<#ty>
}
} else {
quote! {
::deser::__derive::Option<#ty>
}
}
})
.collect::<Vec<_>>();
let sink_defaults = attrs
.iter()
.map(|f| {
if f.flatten() {
quote! {
::deser::de::OwnedSink::deserialize()
}
} else {
quote! {
::deser::__derive::None
}
}
})
.collect::<Vec<_>>();

let mut seen_names = HashSet::new();
let mut first_duplicate_name = None;
let matcher = attrs
.iter()
.map(|x| {
.zip(sink_fieldname.iter())
.filter_map(|(x, fieldname)| {
if x.flatten() {
return None;
}

let name = x.name(&container_attrs).to_string();
if first_duplicate_name.is_none() && seen_names.contains(&name) {
first_duplicate_name = Some((name.clone(), x.field()));
}
seen_names.insert(name.clone());

let mut rv = quote! {
::deser::__derive::Some(#name)
};
let mut rv = quote! { #name };
for alias in x.aliases() {
let alias = alias.clone();
if first_duplicate_name.is_none() && seen_names.contains(&alias) {
first_duplicate_name = Some((alias.clone(), x.field()));
}
seen_names.insert(alias.clone());
rv = quote! {
#rv | ::deser::__derive::Some(#alias)
};
rv = quote! { #rv | #alias };
}
rv
Some(quote! {
#rv => return ::deser::__derive::Ok(::deser::__derive::Some(::deser::Deserialize::deserialize_into(&mut self.#fieldname))),
})
})
.collect::<Vec<_>>();

Expand Down Expand Up @@ -103,6 +133,17 @@ fn derive_struct(input: &syn::DeriveInput, fields: &syn::FieldsNamed) -> syn::Re
.map(|(name, attrs)| {
if attrs.default().is_some() {
quote! { #name }
} else if attrs.flatten() {
// this should never happen unless the inner deserializer fucked up
let error = format!(
"Failed to deserialize flattened field '{}'",
attrs.name(&container_attrs)
);
quote! {
#name.ok_or_else(|| {
::deser::Error::new(::deser::ErrorKind::Unexpected, #error)
})?
}
} else if container_attrs.default().is_some() {
quote! { #name.unwrap() }
} else {
Expand All @@ -115,6 +156,19 @@ fn derive_struct(input: &syn::DeriveInput, fields: &syn::FieldsNamed) -> syn::Re
}
})
.collect::<Vec<_>>();
let flatten_fields = sink_fieldname
.iter()
.zip(attrs.iter())
.filter_map(
|(name, attrs)| {
if attrs.flatten() {
Some(name)
} else {
None
}
},
)
.collect::<Vec<_>>();

let stage2_default = if container_attrs.default().is_some() {
let need_container_default = sink_fieldname
Expand Down Expand Up @@ -164,10 +218,11 @@ fn derive_struct(input: &syn::DeriveInput, fields: &syn::FieldsNamed) -> syn::Re
slot: &'__a mut ::deser::__derive::Option<#ident #ty_generics>,
key: ::deser::__derive::Option<String>,
#(
#sink_fieldname: ::deser::__derive::Option<#fieldty>,
#sink_fieldname: #sink_fieldty,
)*
}

#[automatically_derived]
impl #impl_generics ::deser::Deserialize for #ident #ty_generics #bounded_where_clause {
fn deserialize_into(
__slot: &mut ::deser::__derive::Option<Self>,
Expand All @@ -176,12 +231,13 @@ fn derive_struct(input: &syn::DeriveInput, fields: &syn::FieldsNamed) -> syn::Re
slot: __slot,
key: ::deser::__derive::None,
#(
#sink_fieldname: ::deser::__derive::None,
#sink_fieldname: #sink_defaults,
)*
})
}
}

#[automatically_derived]
impl #wrapper_impl_generics ::deser::de::Sink for __Sink #wrapper_ty_generics #bounded_where_clause {
fn descriptor(&self) -> &dyn ::deser::Descriptor {
&__Descriptor
Expand All @@ -202,16 +258,36 @@ fn derive_struct(input: &syn::DeriveInput, fields: &syn::FieldsNamed) -> syn::Re
fn next_value(&mut self, __state: &::deser::de::DeserializerState)
-> ::deser::__derive::Result<::deser::de::SinkHandle>
{
match self.key.take().as_deref() {
let __key = self.key.take().unwrap();
::deser::__derive::Ok(match self.value_for_key(&__key, __state)? {
::deser::__derive::Some(__sink) => __sink,
::deser::__derive::None => ::deser::de::SinkHandle::null(),
})
}

fn value_for_key(&mut self, __key: &str, __state: &::deser::de::DeserializerState)
-> ::deser::__derive::Result<::deser::__derive::Option<::deser::de::SinkHandle>>
{
match __key {
#(
#matcher => ::deser::__derive::Ok(::deser::Deserialize::deserialize_into(&mut self.#sink_fieldname)),
#matcher
)*
_ => ::deser::__derive::Ok(::deser::de::SinkHandle::null()),
__other => {
#(
if let ::deser::__derive::Some(__sink) = self.#flatten_fields.borrow_mut().value_for_key(__other, __state)? {
return ::deser::__derive::Ok(::deser::__derive::Some(__sink));
}
)*
}
}
::deser::__derive::Ok(::deser::__derive::None)
}

fn finish(&mut self, __state: &::deser::de::DeserializerState) -> ::deser::__derive::Result<()> {
#![allow(unused_mut)]
#(
self.#flatten_fields.borrow_mut().finish(__state)?;
)*
#(
let mut #sink_fieldname = self.#sink_fieldname.#field_stage1_default;
)*
Expand Down Expand Up @@ -316,6 +392,7 @@ pub fn derive_enum(
slot: ::deser::__derive::Option<#ident>,
}

#[automatically_derived]
impl ::deser::de::Deserialize for #ident {
fn deserialize_into(
__slot: &mut ::deser::__derive::Option<Self>
Expand Down
Loading

0 comments on commit 78a2e7a

Please sign in to comment.