Skip to content

Commit

Permalink
Add support for packed structs.
Browse files Browse the repository at this point in the history
  • Loading branch information
05storm26 authored and dtolnay committed May 10, 2020
1 parent d6b39fd commit 9f47c47
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 2 deletions.
27 changes: 27 additions & 0 deletions serde_derive/src/internals/attr.rs
Expand Up @@ -222,6 +222,7 @@ pub struct Container {
identifier: Identifier,
has_flatten: bool,
serde_path: Option<syn::Path>,
is_packed: bool,
}

/// Styles of representing an enum.
Expand Down Expand Up @@ -592,6 +593,27 @@ impl Container {
}
}

use proc_macro2::Delimiter;
let is_packed = item.attrs.iter().any(|attr| {
match attr.style {
syn::AttrStyle::Outer => attr
.path
.get_ident()
.map_or(false, |ident| *ident == "repr")
&& syn::parse2::<Group>(attr.tokens.clone())
.ok()
.filter(|g| g.delimiter() == Delimiter::Parenthesis)
.map(|g| g.stream().to_string())
.map_or(false, |repr| {
let repr = repr.trim();
repr == "packed"
|| repr.starts_with("packed(")
|| repr.starts_with("packed ")
}),
_ => false
}
});

Container {
name: Name::from_attrs(unraw(&item.ident), ser_name, de_name, None),
transparent: transparent.get(),
Expand All @@ -611,6 +633,7 @@ impl Container {
identifier: decide_identifier(cx, item, field_identifier, variant_identifier),
has_flatten: false,
serde_path: serde_path.get(),
is_packed,
}
}

Expand Down Expand Up @@ -662,6 +685,10 @@ impl Container {
self.remote.as_ref()
}

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

pub fn identifier(&self) -> Identifier {
self.identifier
}
Expand Down
20 changes: 18 additions & 2 deletions serde_derive/src/ser.rs
Expand Up @@ -87,6 +87,9 @@ struct Parameters {

/// Type has a `serde(remote = "...")` attribute.
is_remote: bool,

/// Type has a repr(packed) attribute.
is_packed: bool,
}

impl Parameters {
Expand All @@ -103,13 +106,16 @@ impl Parameters {
None => cont.ident.clone().into(),
};

let is_packed = cont.attrs.is_packed();

let generics = build_generics(cont);

Parameters {
self_var,
this,
generics,
is_remote,
is_packed,
}
}

Expand Down Expand Up @@ -1238,9 +1244,19 @@ fn mut_if(is_mut: bool) -> Option<TokenStream> {
fn get_member(params: &Parameters, field: &Field, member: &Member) -> TokenStream {
let self_var = &params.self_var;
match (params.is_remote, field.attrs.getter()) {
(false, None) => quote!(&#self_var.#member),
(false, None) => {
if params.is_packed {
quote!(&{let copy = #self_var.#member; copy })
} else {
quote!(&#self_var.#member)
}
}
(true, None) => {
let inner = quote!(&#self_var.#member);
let inner = if params.is_packed {
quote!(&{let copy = #self_var.#member; copy })
} else {
quote!(&#self_var.#member)
};
let ty = field.ty;
quote!(_serde::private::ser::constrain::<#ty>(#inner))
}
Expand Down

0 comments on commit 9f47c47

Please sign in to comment.