| use internals::symbol::*; |
| use internals::{ungroup, Ctxt}; |
| use proc_macro2::{Spacing, Span, TokenStream, TokenTree}; |
| use quote::ToTokens; |
| use std::borrow::Cow; |
| use std::collections::BTreeSet; |
| use std::iter::FromIterator; |
| use syn; |
| use syn::meta::ParseNestedMeta; |
| use syn::parse::ParseStream; |
| use syn::punctuated::Punctuated; |
| use syn::{token, Ident, Lifetime}; |
| |
| // This module handles parsing of `#[serde(...)]` attributes. The entrypoints |
| // are `attr::Container::from_ast`, `attr::Variant::from_ast`, and |
| // `attr::Field::from_ast`. Each returns an instance of the corresponding |
| // struct. Note that none of them return a Result. Unrecognized, malformed, or |
| // duplicated attributes result in a span_err but otherwise are ignored. The |
| // user will see errors simultaneously for all bad attributes in the crate |
| // rather than just the first. |
| |
| pub use internals::case::RenameRule; |
| |
| struct Attr<'c, T> { |
| cx: &'c Ctxt, |
| name: Symbol, |
| tokens: TokenStream, |
| value: Option<T>, |
| } |
| |
| impl<'c, T> Attr<'c, T> { |
| fn none(cx: &'c Ctxt, name: Symbol) -> Self { |
| Attr { |
| cx, |
| name, |
| tokens: TokenStream::new(), |
| value: None, |
| } |
| } |
| |
| fn set<A: ToTokens>(&mut self, obj: A, value: T) { |
| let tokens = obj.into_token_stream(); |
| |
| if self.value.is_some() { |
| let msg = format!("duplicate serde attribute `{}`", self.name); |
| self.cx.error_spanned_by(tokens, msg); |
| } else { |
| self.tokens = tokens; |
| self.value = Some(value); |
| } |
| } |
| |
| fn set_opt<A: ToTokens>(&mut self, obj: A, value: Option<T>) { |
| if let Some(value) = value { |
| self.set(obj, value); |
| } |
| } |
| |
| fn set_if_none(&mut self, value: T) { |
| if self.value.is_none() { |
| self.value = Some(value); |
| } |
| } |
| |
| fn get(self) -> Option<T> { |
| self.value |
| } |
| |
| fn get_with_tokens(self) -> Option<(TokenStream, T)> { |
| match self.value { |
| Some(v) => Some((self.tokens, v)), |
| None => None, |
| } |
| } |
| } |
| |
| struct BoolAttr<'c>(Attr<'c, ()>); |
| |
| impl<'c> BoolAttr<'c> { |
| fn none(cx: &'c Ctxt, name: Symbol) -> Self { |
| BoolAttr(Attr::none(cx, name)) |
| } |
| |
| fn set_true<A: ToTokens>(&mut self, obj: A) { |
| self.0.set(obj, ()); |
| } |
| |
| fn get(&self) -> bool { |
| self.0.value.is_some() |
| } |
| } |
| |
| struct VecAttr<'c, T> { |
| cx: &'c Ctxt, |
| name: Symbol, |
| first_dup_tokens: TokenStream, |
| values: Vec<T>, |
| } |
| |
| impl<'c, T> VecAttr<'c, T> { |
| fn none(cx: &'c Ctxt, name: Symbol) -> Self { |
| VecAttr { |
| cx, |
| name, |
| first_dup_tokens: TokenStream::new(), |
| values: Vec::new(), |
| } |
| } |
| |
| fn insert<A: ToTokens>(&mut self, obj: A, value: T) { |
| if self.values.len() == 1 { |
| self.first_dup_tokens = obj.into_token_stream(); |
| } |
| self.values.push(value); |
| } |
| |
| fn at_most_one(mut self) -> Option<T> { |
| if self.values.len() > 1 { |
| let dup_token = self.first_dup_tokens; |
| let msg = format!("duplicate serde attribute `{}`", self.name); |
| self.cx.error_spanned_by(dup_token, msg); |
| None |
| } else { |
| self.values.pop() |
| } |
| } |
| |
| fn get(self) -> Vec<T> { |
| self.values |
| } |
| } |
| |
| pub struct Name { |
| serialize: String, |
| serialize_renamed: bool, |
| deserialize: String, |
| deserialize_renamed: bool, |
| deserialize_aliases: Vec<String>, |
| } |
| |
| fn unraw(ident: &Ident) -> String { |
| ident.to_string().trim_start_matches("r#").to_owned() |
| } |
| |
| impl Name { |
| fn from_attrs( |
| source_name: String, |
| ser_name: Attr<String>, |
| de_name: Attr<String>, |
| de_aliases: Option<VecAttr<String>>, |
| ) -> Name { |
| let deserialize_aliases = match de_aliases { |
| Some(de_aliases) => { |
| let mut alias_list = BTreeSet::new(); |
| for alias_name in de_aliases.get() { |
| alias_list.insert(alias_name); |
| } |
| alias_list.into_iter().collect() |
| } |
| None => Vec::new(), |
| }; |
| |
| let ser_name = ser_name.get(); |
| let ser_renamed = ser_name.is_some(); |
| let de_name = de_name.get(); |
| let de_renamed = de_name.is_some(); |
| Name { |
| serialize: ser_name.unwrap_or_else(|| source_name.clone()), |
| serialize_renamed: ser_renamed, |
| deserialize: de_name.unwrap_or(source_name), |
| deserialize_renamed: de_renamed, |
| deserialize_aliases, |
| } |
| } |
| |
| /// Return the container name for the container when serializing. |
| pub fn serialize_name(&self) -> String { |
| self.serialize.clone() |
| } |
| |
| /// Return the container name for the container when deserializing. |
| pub fn deserialize_name(&self) -> String { |
| self.deserialize.clone() |
| } |
| |
| fn deserialize_aliases(&self) -> Vec<String> { |
| let mut aliases = self.deserialize_aliases.clone(); |
| let main_name = self.deserialize_name(); |
| if !aliases.contains(&main_name) { |
| aliases.push(main_name); |
| } |
| aliases |
| } |
| } |
| |
| pub struct RenameAllRules { |
| serialize: RenameRule, |
| deserialize: RenameRule, |
| } |
| |
| /// Represents struct or enum attribute information. |
| pub struct Container { |
| name: Name, |
| transparent: bool, |
| deny_unknown_fields: bool, |
| default: Default, |
| rename_all_rules: RenameAllRules, |
| ser_bound: Option<Vec<syn::WherePredicate>>, |
| de_bound: Option<Vec<syn::WherePredicate>>, |
| tag: TagType, |
| type_from: Option<syn::Type>, |
| type_try_from: Option<syn::Type>, |
| type_into: Option<syn::Type>, |
| remote: Option<syn::Path>, |
| identifier: Identifier, |
| has_flatten: bool, |
| serde_path: Option<syn::Path>, |
| is_packed: bool, |
| /// Error message generated when type can't be deserialized |
| expecting: Option<String>, |
| } |
| |
| /// Styles of representing an enum. |
| pub enum TagType { |
| /// The default. |
| /// |
| /// ```json |
| /// {"variant1": {"key1": "value1", "key2": "value2"}} |
| /// ``` |
| External, |
| |
| /// `#[serde(tag = "type")]` |
| /// |
| /// ```json |
| /// {"type": "variant1", "key1": "value1", "key2": "value2"} |
| /// ``` |
| Internal { tag: String }, |
| |
| /// `#[serde(tag = "t", content = "c")]` |
| /// |
| /// ```json |
| /// {"t": "variant1", "c": {"key1": "value1", "key2": "value2"}} |
| /// ``` |
| Adjacent { tag: String, content: String }, |
| |
| /// `#[serde(untagged)]` |
| /// |
| /// ```json |
| /// {"key1": "value1", "key2": "value2"} |
| /// ``` |
| None, |
| } |
| |
| /// Whether this enum represents the fields of a struct or the variants of an |
| /// enum. |
| #[derive(Copy, Clone)] |
| pub enum Identifier { |
| /// It does not. |
| No, |
| |
| /// This enum represents the fields of a struct. All of the variants must be |
| /// unit variants, except possibly one which is annotated with |
| /// `#[serde(other)]` and is a newtype variant. |
| Field, |
| |
| /// This enum represents the variants of an enum. All of the variants must |
| /// be unit variants. |
| Variant, |
| } |
| |
| impl Identifier { |
| #[cfg(feature = "deserialize_in_place")] |
| pub fn is_some(self) -> bool { |
| match self { |
| Identifier::No => false, |
| Identifier::Field | Identifier::Variant => true, |
| } |
| } |
| } |
| |
| impl Container { |
| /// Extract out the `#[serde(...)]` attributes from an item. |
| pub fn from_ast(cx: &Ctxt, item: &syn::DeriveInput) -> Self { |
| let mut ser_name = Attr::none(cx, RENAME); |
| let mut de_name = Attr::none(cx, RENAME); |
| let mut transparent = BoolAttr::none(cx, TRANSPARENT); |
| let mut deny_unknown_fields = BoolAttr::none(cx, DENY_UNKNOWN_FIELDS); |
| let mut default = Attr::none(cx, DEFAULT); |
| let mut rename_all_ser_rule = Attr::none(cx, RENAME_ALL); |
| let mut rename_all_de_rule = Attr::none(cx, RENAME_ALL); |
| let mut ser_bound = Attr::none(cx, BOUND); |
| let mut de_bound = Attr::none(cx, BOUND); |
| let mut untagged = BoolAttr::none(cx, UNTAGGED); |
| let mut internal_tag = Attr::none(cx, TAG); |
| let mut content = Attr::none(cx, CONTENT); |
| let mut type_from = Attr::none(cx, FROM); |
| let mut type_try_from = Attr::none(cx, TRY_FROM); |
| let mut type_into = Attr::none(cx, INTO); |
| let mut remote = Attr::none(cx, REMOTE); |
| let mut field_identifier = BoolAttr::none(cx, FIELD_IDENTIFIER); |
| let mut variant_identifier = BoolAttr::none(cx, VARIANT_IDENTIFIER); |
| let mut serde_path = Attr::none(cx, CRATE); |
| let mut expecting = Attr::none(cx, EXPECTING); |
| |
| for attr in &item.attrs { |
| if attr.path() != SERDE { |
| continue; |
| } |
| |
| if let Err(err) = attr.parse_nested_meta(|meta| { |
| if meta.path == RENAME { |
| // #[serde(rename = "foo")] |
| // #[serde(rename(serialize = "foo", deserialize = "bar"))] |
| let (ser, de) = get_renames(cx, RENAME, &meta)?; |
| ser_name.set_opt(&meta.path, ser.as_ref().map(syn::LitStr::value)); |
| de_name.set_opt(&meta.path, de.as_ref().map(syn::LitStr::value)); |
| } else if meta.path == RENAME_ALL { |
| // #[serde(rename_all = "foo")] |
| // #[serde(rename_all(serialize = "foo", deserialize = "bar"))] |
| let one_name = meta.input.peek(Token![=]); |
| let (ser, de) = get_renames(cx, RENAME_ALL, &meta)?; |
| if let Some(ser) = ser { |
| match RenameRule::from_str(&ser.value()) { |
| Ok(rename_rule) => rename_all_ser_rule.set(&meta.path, rename_rule), |
| Err(err) => cx.error_spanned_by(ser, err), |
| } |
| } |
| if let Some(de) = de { |
| match RenameRule::from_str(&de.value()) { |
| Ok(rename_rule) => rename_all_de_rule.set(&meta.path, rename_rule), |
| Err(err) => { |
| if !one_name { |
| cx.error_spanned_by(de, err); |
| } |
| } |
| } |
| } |
| } else if meta.path == TRANSPARENT { |
| // #[serde(transparent)] |
| transparent.set_true(meta.path); |
| } else if meta.path == DENY_UNKNOWN_FIELDS { |
| // #[serde(deny_unknown_fields)] |
| deny_unknown_fields.set_true(meta.path); |
| } else if meta.path == DEFAULT { |
| if meta.input.peek(Token![=]) { |
| // #[serde(default = "...")] |
| if let Some(path) = parse_lit_into_expr_path(cx, DEFAULT, &meta)? { |
| match &item.data { |
| syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields { |
| syn::Fields::Named(_) => { |
| default.set(&meta.path, Default::Path(path)); |
| } |
| syn::Fields::Unnamed(_) | syn::Fields::Unit => { |
| let msg = "#[serde(default = \"...\")] can only be used on structs with named fields"; |
| cx.error_spanned_by(fields, msg); |
| } |
| }, |
| syn::Data::Enum(syn::DataEnum { enum_token, .. }) => { |
| let msg = "#[serde(default = \"...\")] can only be used on structs with named fields"; |
| cx.error_spanned_by(enum_token, msg); |
| } |
| syn::Data::Union(syn::DataUnion { union_token, .. }) => { |
| let msg = "#[serde(default = \"...\")] can only be used on structs with named fields"; |
| cx.error_spanned_by(union_token, msg); |
| } |
| } |
| } |
| } else { |
| // #[serde(default)] |
| match &item.data { |
| syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields { |
| syn::Fields::Named(_) => { |
| default.set(meta.path, Default::Default); |
| } |
| syn::Fields::Unnamed(_) | syn::Fields::Unit => { |
| let msg = "#[serde(default)] can only be used on structs with named fields"; |
| cx.error_spanned_by(fields, msg); |
| } |
| }, |
| syn::Data::Enum(syn::DataEnum { enum_token, .. }) => { |
| let msg = "#[serde(default)] can only be used on structs with named fields"; |
| cx.error_spanned_by(enum_token, msg); |
| } |
| syn::Data::Union(syn::DataUnion { union_token, .. }) => { |
| let msg = "#[serde(default)] can only be used on structs with named fields"; |
| cx.error_spanned_by(union_token, msg); |
| } |
| } |
| } |
| } else if meta.path == BOUND { |
| // #[serde(bound = "T: SomeBound")] |
| // #[serde(bound(serialize = "...", deserialize = "..."))] |
| let (ser, de) = get_where_predicates(cx, &meta)?; |
| ser_bound.set_opt(&meta.path, ser); |
| de_bound.set_opt(&meta.path, de); |
| } else if meta.path == UNTAGGED { |
| // #[serde(untagged)] |
| match item.data { |
| syn::Data::Enum(_) => { |
| untagged.set_true(&meta.path); |
| } |
| syn::Data::Struct(syn::DataStruct { struct_token, .. }) => { |
| let msg = "#[serde(untagged)] can only be used on enums"; |
| cx.error_spanned_by(struct_token, msg); |
| } |
| syn::Data::Union(syn::DataUnion { union_token, .. }) => { |
| let msg = "#[serde(untagged)] can only be used on enums"; |
| cx.error_spanned_by(union_token, msg); |
| } |
| } |
| } else if meta.path == TAG { |
| // #[serde(tag = "type")] |
| if let Some(s) = get_lit_str(cx, TAG, &meta)? { |
| match &item.data { |
| syn::Data::Enum(_) => { |
| internal_tag.set(&meta.path, s.value()); |
| } |
| syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields { |
| syn::Fields::Named(_) => { |
| internal_tag.set(&meta.path, s.value()); |
| } |
| syn::Fields::Unnamed(_) | syn::Fields::Unit => { |
| let msg = "#[serde(tag = \"...\")] can only be used on enums and structs with named fields"; |
| cx.error_spanned_by(fields, msg); |
| } |
| }, |
| syn::Data::Union(syn::DataUnion { union_token, .. }) => { |
| let msg = "#[serde(tag = \"...\")] can only be used on enums and structs with named fields"; |
| cx.error_spanned_by(union_token, msg); |
| } |
| } |
| } |
| } else if meta.path == CONTENT { |
| // #[serde(content = "c")] |
| if let Some(s) = get_lit_str(cx, CONTENT, &meta)? { |
| match &item.data { |
| syn::Data::Enum(_) => { |
| content.set(&meta.path, s.value()); |
| } |
| syn::Data::Struct(syn::DataStruct { struct_token, .. }) => { |
| let msg = "#[serde(content = \"...\")] can only be used on enums"; |
| cx.error_spanned_by(struct_token, msg); |
| } |
| syn::Data::Union(syn::DataUnion { union_token, .. }) => { |
| let msg = "#[serde(content = \"...\")] can only be used on enums"; |
| cx.error_spanned_by(union_token, msg); |
| } |
| } |
| } |
| } else if meta.path == FROM { |
| // #[serde(from = "Type")] |
| if let Some(from_ty) = parse_lit_into_ty(cx, FROM, &meta)? { |
| type_from.set_opt(&meta.path, Some(from_ty)); |
| } |
| } else if meta.path == TRY_FROM { |
| // #[serde(try_from = "Type")] |
| if let Some(try_from_ty) = parse_lit_into_ty(cx, TRY_FROM, &meta)? { |
| type_try_from.set_opt(&meta.path, Some(try_from_ty)); |
| } |
| } else if meta.path == INTO { |
| // #[serde(into = "Type")] |
| if let Some(into_ty) = parse_lit_into_ty(cx, INTO, &meta)? { |
| type_into.set_opt(&meta.path, Some(into_ty)); |
| } |
| } else if meta.path == REMOTE { |
| // #[serde(remote = "...")] |
| if let Some(path) = parse_lit_into_path(cx, REMOTE, &meta)? { |
| if is_primitive_path(&path, "Self") { |
| remote.set(&meta.path, item.ident.clone().into()); |
| } else { |
| remote.set(&meta.path, path); |
| } |
| } |
| } else if meta.path == FIELD_IDENTIFIER { |
| // #[serde(field_identifier)] |
| field_identifier.set_true(&meta.path); |
| } else if meta.path == VARIANT_IDENTIFIER { |
| // #[serde(variant_identifier)] |
| variant_identifier.set_true(&meta.path); |
| } else if meta.path == CRATE { |
| // #[serde(crate = "foo")] |
| if let Some(path) = parse_lit_into_path(cx, CRATE, &meta)? { |
| serde_path.set(&meta.path, path); |
| } |
| } else if meta.path == EXPECTING { |
| // #[serde(expecting = "a message")] |
| if let Some(s) = get_lit_str(cx, EXPECTING, &meta)? { |
| expecting.set(&meta.path, s.value()); |
| } |
| } else { |
| let path = meta.path.to_token_stream().to_string().replace(' ', ""); |
| return Err( |
| meta.error(format_args!("unknown serde container attribute `{}`", path)) |
| ); |
| } |
| Ok(()) |
| }) { |
| cx.syn_error(err); |
| } |
| } |
| |
| let mut is_packed = false; |
| for attr in &item.attrs { |
| if attr.path() == REPR { |
| let _ = attr.parse_args_with(|input: ParseStream| { |
| while let Some(token) = input.parse()? { |
| if let TokenTree::Ident(ident) = token { |
| is_packed |= ident == "packed"; |
| } |
| } |
| Ok(()) |
| }); |
| } |
| } |
| |
| Container { |
| name: Name::from_attrs(unraw(&item.ident), ser_name, de_name, None), |
| transparent: transparent.get(), |
| deny_unknown_fields: deny_unknown_fields.get(), |
| default: default.get().unwrap_or(Default::None), |
| rename_all_rules: RenameAllRules { |
| serialize: rename_all_ser_rule.get().unwrap_or(RenameRule::None), |
| deserialize: rename_all_de_rule.get().unwrap_or(RenameRule::None), |
| }, |
| ser_bound: ser_bound.get(), |
| de_bound: de_bound.get(), |
| tag: decide_tag(cx, item, untagged, internal_tag, content), |
| type_from: type_from.get(), |
| type_try_from: type_try_from.get(), |
| type_into: type_into.get(), |
| remote: remote.get(), |
| identifier: decide_identifier(cx, item, field_identifier, variant_identifier), |
| has_flatten: false, |
| serde_path: serde_path.get(), |
| is_packed, |
| expecting: expecting.get(), |
| } |
| } |
| |
| pub fn name(&self) -> &Name { |
| &self.name |
| } |
| |
| pub fn rename_all_rules(&self) -> &RenameAllRules { |
| &self.rename_all_rules |
| } |
| |
| pub fn transparent(&self) -> bool { |
| self.transparent |
| } |
| |
| pub fn deny_unknown_fields(&self) -> bool { |
| self.deny_unknown_fields |
| } |
| |
| pub fn default(&self) -> &Default { |
| &self.default |
| } |
| |
| pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> { |
| self.ser_bound.as_ref().map(|vec| &vec[..]) |
| } |
| |
| pub fn de_bound(&self) -> Option<&[syn::WherePredicate]> { |
| self.de_bound.as_ref().map(|vec| &vec[..]) |
| } |
| |
| pub fn tag(&self) -> &TagType { |
| &self.tag |
| } |
| |
| pub fn type_from(&self) -> Option<&syn::Type> { |
| self.type_from.as_ref() |
| } |
| |
| pub fn type_try_from(&self) -> Option<&syn::Type> { |
| self.type_try_from.as_ref() |
| } |
| |
| pub fn type_into(&self) -> Option<&syn::Type> { |
| self.type_into.as_ref() |
| } |
| |
| pub fn remote(&self) -> Option<&syn::Path> { |
| self.remote.as_ref() |
| } |
| |
| pub fn is_packed(&self) -> bool { |
| self.is_packed |
| } |
| |
| pub fn identifier(&self) -> Identifier { |
| self.identifier |
| } |
| |
| pub fn has_flatten(&self) -> bool { |
| self.has_flatten |
| } |
| |
| pub fn mark_has_flatten(&mut self) { |
| self.has_flatten = true; |
| } |
| |
| pub fn custom_serde_path(&self) -> Option<&syn::Path> { |
| self.serde_path.as_ref() |
| } |
| |
| pub fn serde_path(&self) -> Cow<syn::Path> { |
| self.custom_serde_path() |
| .map_or_else(|| Cow::Owned(parse_quote!(_serde)), Cow::Borrowed) |
| } |
| |
| /// Error message generated when type can't be deserialized. |
| /// If `None`, default message will be used |
| pub fn expecting(&self) -> Option<&str> { |
| self.expecting.as_ref().map(String::as_ref) |
| } |
| } |
| |
| fn decide_tag( |
| cx: &Ctxt, |
| item: &syn::DeriveInput, |
| untagged: BoolAttr, |
| internal_tag: Attr<String>, |
| content: Attr<String>, |
| ) -> TagType { |
| match ( |
| untagged.0.get_with_tokens(), |
| internal_tag.get_with_tokens(), |
| content.get_with_tokens(), |
| ) { |
| (None, None, None) => TagType::External, |
| (Some(_), None, None) => TagType::None, |
| (None, Some((_, tag)), None) => { |
| // Check that there are no tuple variants. |
| if let syn::Data::Enum(data) = &item.data { |
| for variant in &data.variants { |
| match &variant.fields { |
| syn::Fields::Named(_) | syn::Fields::Unit => {} |
| syn::Fields::Unnamed(fields) => { |
| if fields.unnamed.len() != 1 { |
| let msg = |
| "#[serde(tag = \"...\")] cannot be used with tuple variants"; |
| cx.error_spanned_by(variant, msg); |
| break; |
| } |
| } |
| } |
| } |
| } |
| TagType::Internal { tag } |
| } |
| (Some((untagged_tokens, _)), Some((tag_tokens, _)), None) => { |
| let msg = "enum cannot be both untagged and internally tagged"; |
| cx.error_spanned_by(untagged_tokens, msg); |
| cx.error_spanned_by(tag_tokens, msg); |
| TagType::External // doesn't matter, will error |
| } |
| (None, None, Some((content_tokens, _))) => { |
| let msg = "#[serde(tag = \"...\", content = \"...\")] must be used together"; |
| cx.error_spanned_by(content_tokens, msg); |
| TagType::External |
| } |
| (Some((untagged_tokens, _)), None, Some((content_tokens, _))) => { |
| let msg = "untagged enum cannot have #[serde(content = \"...\")]"; |
| cx.error_spanned_by(untagged_tokens, msg); |
| cx.error_spanned_by(content_tokens, msg); |
| TagType::External |
| } |
| (None, Some((_, tag)), Some((_, content))) => TagType::Adjacent { tag, content }, |
| (Some((untagged_tokens, _)), Some((tag_tokens, _)), Some((content_tokens, _))) => { |
| let msg = "untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]"; |
| cx.error_spanned_by(untagged_tokens, msg); |
| cx.error_spanned_by(tag_tokens, msg); |
| cx.error_spanned_by(content_tokens, msg); |
| TagType::External |
| } |
| } |
| } |
| |
| fn decide_identifier( |
| cx: &Ctxt, |
| item: &syn::DeriveInput, |
| field_identifier: BoolAttr, |
| variant_identifier: BoolAttr, |
| ) -> Identifier { |
| match ( |
| &item.data, |
| field_identifier.0.get_with_tokens(), |
| variant_identifier.0.get_with_tokens(), |
| ) { |
| (_, None, None) => Identifier::No, |
| (_, Some((field_identifier_tokens, _)), Some((variant_identifier_tokens, _))) => { |
| let msg = |
| "#[serde(field_identifier)] and #[serde(variant_identifier)] cannot both be set"; |
| cx.error_spanned_by(field_identifier_tokens, msg); |
| cx.error_spanned_by(variant_identifier_tokens, msg); |
| Identifier::No |
| } |
| (syn::Data::Enum(_), Some(_), None) => Identifier::Field, |
| (syn::Data::Enum(_), None, Some(_)) => Identifier::Variant, |
| (syn::Data::Struct(syn::DataStruct { struct_token, .. }), Some(_), None) => { |
| let msg = "#[serde(field_identifier)] can only be used on an enum"; |
| cx.error_spanned_by(struct_token, msg); |
| Identifier::No |
| } |
| (syn::Data::Union(syn::DataUnion { union_token, .. }), Some(_), None) => { |
| let msg = "#[serde(field_identifier)] can only be used on an enum"; |
| cx.error_spanned_by(union_token, msg); |
| Identifier::No |
| } |
| (syn::Data::Struct(syn::DataStruct { struct_token, .. }), None, Some(_)) => { |
| let msg = "#[serde(variant_identifier)] can only be used on an enum"; |
| cx.error_spanned_by(struct_token, msg); |
| Identifier::No |
| } |
| (syn::Data::Union(syn::DataUnion { union_token, .. }), None, Some(_)) => { |
| let msg = "#[serde(variant_identifier)] can only be used on an enum"; |
| cx.error_spanned_by(union_token, msg); |
| Identifier::No |
| } |
| } |
| } |
| |
| /// Represents variant attribute information |
| pub struct Variant { |
| name: Name, |
| rename_all_rules: RenameAllRules, |
| ser_bound: Option<Vec<syn::WherePredicate>>, |
| de_bound: Option<Vec<syn::WherePredicate>>, |
| skip_deserializing: bool, |
| skip_serializing: bool, |
| other: bool, |
| serialize_with: Option<syn::ExprPath>, |
| deserialize_with: Option<syn::ExprPath>, |
| borrow: Option<BorrowAttribute>, |
| } |
| |
| struct BorrowAttribute { |
| path: syn::Path, |
| lifetimes: Option<BTreeSet<syn::Lifetime>>, |
| } |
| |
| impl Variant { |
| pub fn from_ast(cx: &Ctxt, variant: &syn::Variant) -> Self { |
| let mut ser_name = Attr::none(cx, RENAME); |
| let mut de_name = Attr::none(cx, RENAME); |
| let mut de_aliases = VecAttr::none(cx, RENAME); |
| let mut skip_deserializing = BoolAttr::none(cx, SKIP_DESERIALIZING); |
| let mut skip_serializing = BoolAttr::none(cx, SKIP_SERIALIZING); |
| let mut rename_all_ser_rule = Attr::none(cx, RENAME_ALL); |
| let mut rename_all_de_rule = Attr::none(cx, RENAME_ALL); |
| let mut ser_bound = Attr::none(cx, BOUND); |
| let mut de_bound = Attr::none(cx, BOUND); |
| let mut other = BoolAttr::none(cx, OTHER); |
| let mut serialize_with = Attr::none(cx, SERIALIZE_WITH); |
| let mut deserialize_with = Attr::none(cx, DESERIALIZE_WITH); |
| let mut borrow = Attr::none(cx, BORROW); |
| |
| for attr in &variant.attrs { |
| if attr.path() != SERDE { |
| continue; |
| } |
| |
| if let Err(err) = attr.parse_nested_meta(|meta| { |
| if meta.path == RENAME { |
| // #[serde(rename = "foo")] |
| // #[serde(rename(serialize = "foo", deserialize = "bar"))] |
| let (ser, de) = get_multiple_renames(cx, &meta)?; |
| ser_name.set_opt(&meta.path, ser.as_ref().map(syn::LitStr::value)); |
| for de_value in de { |
| de_name.set_if_none(de_value.value()); |
| de_aliases.insert(&meta.path, de_value.value()); |
| } |
| } else if meta.path == ALIAS { |
| // #[serde(alias = "foo")] |
| if let Some(s) = get_lit_str(cx, ALIAS, &meta)? { |
| de_aliases.insert(&meta.path, s.value()); |
| } |
| } else if meta.path == RENAME_ALL { |
| // #[serde(rename_all = "foo")] |
| // #[serde(rename_all(serialize = "foo", deserialize = "bar"))] |
| let one_name = meta.input.peek(Token![=]); |
| let (ser, de) = get_renames(cx, RENAME_ALL, &meta)?; |
| if let Some(ser) = ser { |
| match RenameRule::from_str(&ser.value()) { |
| Ok(rename_rule) => rename_all_ser_rule.set(&meta.path, rename_rule), |
| Err(err) => cx.error_spanned_by(ser, err), |
| } |
| } |
| if let Some(de) = de { |
| match RenameRule::from_str(&de.value()) { |
| Ok(rename_rule) => rename_all_de_rule.set(&meta.path, rename_rule), |
| Err(err) => { |
| if !one_name { |
| cx.error_spanned_by(de, err); |
| } |
| } |
| } |
| } |
| } else if meta.path == SKIP { |
| // #[serde(skip)] |
| skip_serializing.set_true(&meta.path); |
| skip_deserializing.set_true(&meta.path); |
| } else if meta.path == SKIP_DESERIALIZING { |
| // #[serde(skip_deserializing)] |
| skip_deserializing.set_true(&meta.path); |
| } else if meta.path == SKIP_SERIALIZING { |
| // #[serde(skip_serializing)] |
| skip_serializing.set_true(&meta.path); |
| } else if meta.path == OTHER { |
| // #[serde(other)] |
| other.set_true(&meta.path); |
| } else if meta.path == BOUND { |
| // #[serde(bound = "T: SomeBound")] |
| // #[serde(bound(serialize = "...", deserialize = "..."))] |
| let (ser, de) = get_where_predicates(cx, &meta)?; |
| ser_bound.set_opt(&meta.path, ser); |
| de_bound.set_opt(&meta.path, de); |
| } else if meta.path == WITH { |
| // #[serde(with = "...")] |
| if let Some(path) = parse_lit_into_expr_path(cx, WITH, &meta)? { |
| let mut ser_path = path.clone(); |
| ser_path |
| .path |
| .segments |
| .push(Ident::new("serialize", Span::call_site()).into()); |
| serialize_with.set(&meta.path, ser_path); |
| let mut de_path = path; |
| de_path |
| .path |
| .segments |
| .push(Ident::new("deserialize", Span::call_site()).into()); |
| deserialize_with.set(&meta.path, de_path); |
| } |
| } else if meta.path == SERIALIZE_WITH { |
| // #[serde(serialize_with = "...")] |
| if let Some(path) = parse_lit_into_expr_path(cx, SERIALIZE_WITH, &meta)? { |
| serialize_with.set(&meta.path, path); |
| } |
| } else if meta.path == DESERIALIZE_WITH { |
| // #[serde(deserialize_with = "...")] |
| if let Some(path) = parse_lit_into_expr_path(cx, DESERIALIZE_WITH, &meta)? { |
| deserialize_with.set(&meta.path, path); |
| } |
| } else if meta.path == BORROW { |
| let borrow_attribute = if meta.input.peek(Token![=]) { |
| // #[serde(borrow = "'a + 'b")] |
| let lifetimes = parse_lit_into_lifetimes(cx, &meta)?; |
| BorrowAttribute { |
| path: meta.path.clone(), |
| lifetimes: Some(lifetimes), |
| } |
| } else { |
| // #[serde(borrow)] |
| BorrowAttribute { |
| path: meta.path.clone(), |
| lifetimes: None, |
| } |
| }; |
| match &variant.fields { |
| syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => { |
| borrow.set(&meta.path, borrow_attribute); |
| } |
| _ => { |
| let msg = "#[serde(borrow)] may only be used on newtype variants"; |
| cx.error_spanned_by(variant, msg); |
| } |
| } |
| } else { |
| let path = meta.path.to_token_stream().to_string().replace(' ', ""); |
| return Err( |
| meta.error(format_args!("unknown serde variant attribute `{}`", path)) |
| ); |
| } |
| Ok(()) |
| }) { |
| cx.syn_error(err); |
| } |
| } |
| |
| Variant { |
| name: Name::from_attrs(unraw(&variant.ident), ser_name, de_name, Some(de_aliases)), |
| rename_all_rules: RenameAllRules { |
| serialize: rename_all_ser_rule.get().unwrap_or(RenameRule::None), |
| deserialize: rename_all_de_rule.get().unwrap_or(RenameRule::None), |
| }, |
| ser_bound: ser_bound.get(), |
| de_bound: de_bound.get(), |
| skip_deserializing: skip_deserializing.get(), |
| skip_serializing: skip_serializing.get(), |
| other: other.get(), |
| serialize_with: serialize_with.get(), |
| deserialize_with: deserialize_with.get(), |
| borrow: borrow.get(), |
| } |
| } |
| |
| pub fn name(&self) -> &Name { |
| &self.name |
| } |
| |
| pub fn aliases(&self) -> Vec<String> { |
| self.name.deserialize_aliases() |
| } |
| |
| pub fn rename_by_rules(&mut self, rules: &RenameAllRules) { |
| if !self.name.serialize_renamed { |
| self.name.serialize = rules.serialize.apply_to_variant(&self.name.serialize); |
| } |
| if !self.name.deserialize_renamed { |
| self.name.deserialize = rules.deserialize.apply_to_variant(&self.name.deserialize); |
| } |
| } |
| |
| pub fn rename_all_rules(&self) -> &RenameAllRules { |
| &self.rename_all_rules |
| } |
| |
| pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> { |
| self.ser_bound.as_ref().map(|vec| &vec[..]) |
| } |
| |
| pub fn de_bound(&self) -> Option<&[syn::WherePredicate]> { |
| self.de_bound.as_ref().map(|vec| &vec[..]) |
| } |
| |
| pub fn skip_deserializing(&self) -> bool { |
| self.skip_deserializing |
| } |
| |
| pub fn skip_serializing(&self) -> bool { |
| self.skip_serializing |
| } |
| |
| pub fn other(&self) -> bool { |
| self.other |
| } |
| |
| pub fn serialize_with(&self) -> Option<&syn::ExprPath> { |
| self.serialize_with.as_ref() |
| } |
| |
| pub fn deserialize_with(&self) -> Option<&syn::ExprPath> { |
| self.deserialize_with.as_ref() |
| } |
| } |
| |
| /// Represents field attribute information |
| pub struct Field { |
| name: Name, |
| skip_serializing: bool, |
| skip_deserializing: bool, |
| skip_serializing_if: Option<syn::ExprPath>, |
| default: Default, |
| serialize_with: Option<syn::ExprPath>, |
| deserialize_with: Option<syn::ExprPath>, |
| ser_bound: Option<Vec<syn::WherePredicate>>, |
| de_bound: Option<Vec<syn::WherePredicate>>, |
| borrowed_lifetimes: BTreeSet<syn::Lifetime>, |
| getter: Option<syn::ExprPath>, |
| flatten: bool, |
| transparent: bool, |
| } |
| |
| /// Represents the default to use for a field when deserializing. |
| pub enum Default { |
| /// Field must always be specified because it does not have a default. |
| None, |
| /// The default is given by `std::default::Default::default()`. |
| Default, |
| /// The default is given by this function. |
| Path(syn::ExprPath), |
| } |
| |
| impl Default { |
| pub fn is_none(&self) -> bool { |
| match self { |
| Default::None => true, |
| Default::Default | Default::Path(_) => false, |
| } |
| } |
| } |
| |
| impl Field { |
| /// Extract out the `#[serde(...)]` attributes from a struct field. |
| pub fn from_ast( |
| cx: &Ctxt, |
| index: usize, |
| field: &syn::Field, |
| attrs: Option<&Variant>, |
| container_default: &Default, |
| ) -> Self { |
| let mut ser_name = Attr::none(cx, RENAME); |
| let mut de_name = Attr::none(cx, RENAME); |
| let mut de_aliases = VecAttr::none(cx, RENAME); |
| let mut skip_serializing = BoolAttr::none(cx, SKIP_SERIALIZING); |
| let mut skip_deserializing = BoolAttr::none(cx, SKIP_DESERIALIZING); |
| let mut skip_serializing_if = Attr::none(cx, SKIP_SERIALIZING_IF); |
| let mut default = Attr::none(cx, DEFAULT); |
| let mut serialize_with = Attr::none(cx, SERIALIZE_WITH); |
| let mut deserialize_with = Attr::none(cx, DESERIALIZE_WITH); |
| let mut ser_bound = Attr::none(cx, BOUND); |
| let mut de_bound = Attr::none(cx, BOUND); |
| let mut borrowed_lifetimes = Attr::none(cx, BORROW); |
| let mut getter = Attr::none(cx, GETTER); |
| let mut flatten = BoolAttr::none(cx, FLATTEN); |
| |
| let ident = match &field.ident { |
| Some(ident) => unraw(ident), |
| None => index.to_string(), |
| }; |
| |
| if let Some(borrow_attribute) = attrs.and_then(|variant| variant.borrow.as_ref()) { |
| if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, field) { |
| if let Some(lifetimes) = &borrow_attribute.lifetimes { |
| for lifetime in lifetimes { |
| if !borrowable.contains(lifetime) { |
| let msg = |
| format!("field `{}` does not have lifetime {}", ident, lifetime); |
| cx.error_spanned_by(field, msg); |
| } |
| } |
| borrowed_lifetimes.set(&borrow_attribute.path, lifetimes.clone()); |
| } else { |
| borrowed_lifetimes.set(&borrow_attribute.path, borrowable); |
| } |
| } |
| } |
| |
| for attr in &field.attrs { |
| if attr.path() != SERDE { |
| continue; |
| } |
| |
| if let Err(err) = attr.parse_nested_meta(|meta| { |
| if meta.path == RENAME { |
| // #[serde(rename = "foo")] |
| // #[serde(rename(serialize = "foo", deserialize = "bar"))] |
| let (ser, de) = get_multiple_renames(cx, &meta)?; |
| ser_name.set_opt(&meta.path, ser.as_ref().map(syn::LitStr::value)); |
| for de_value in de { |
| de_name.set_if_none(de_value.value()); |
| de_aliases.insert(&meta.path, de_value.value()); |
| } |
| } else if meta.path == ALIAS { |
| // #[serde(alias = "foo")] |
| if let Some(s) = get_lit_str(cx, ALIAS, &meta)? { |
| de_aliases.insert(&meta.path, s.value()); |
| } |
| } else if meta.path == DEFAULT { |
| if meta.input.peek(Token![=]) { |
| // #[serde(default = "...")] |
| if let Some(path) = parse_lit_into_expr_path(cx, DEFAULT, &meta)? { |
| default.set(&meta.path, Default::Path(path)); |
| } |
| } else { |
| // #[serde(default)] |
| default.set(&meta.path, Default::Default); |
| } |
| } else if meta.path == SKIP_SERIALIZING { |
| // #[serde(skip_serializing)] |
| skip_serializing.set_true(&meta.path); |
| } else if meta.path == SKIP_DESERIALIZING { |
| // #[serde(skip_deserializing)] |
| skip_deserializing.set_true(&meta.path); |
| } else if meta.path == SKIP { |
| // #[serde(skip)] |
| skip_serializing.set_true(&meta.path); |
| skip_deserializing.set_true(&meta.path); |
| } else if meta.path == SKIP_SERIALIZING_IF { |
| // #[serde(skip_serializing_if = "...")] |
| if let Some(path) = parse_lit_into_expr_path(cx, SKIP_SERIALIZING_IF, &meta)? { |
| skip_serializing_if.set(&meta.path, path); |
| } |
| } else if meta.path == SERIALIZE_WITH { |
| // #[serde(serialize_with = "...")] |
| if let Some(path) = parse_lit_into_expr_path(cx, SERIALIZE_WITH, &meta)? { |
| serialize_with.set(&meta.path, path); |
| } |
| } else if meta.path == DESERIALIZE_WITH { |
| // #[serde(deserialize_with = "...")] |
| if let Some(path) = parse_lit_into_expr_path(cx, DESERIALIZE_WITH, &meta)? { |
| deserialize_with.set(&meta.path, path); |
| } |
| } else if meta.path == WITH { |
| // #[serde(with = "...")] |
| if let Some(path) = parse_lit_into_expr_path(cx, WITH, &meta)? { |
| let mut ser_path = path.clone(); |
| ser_path |
| .path |
| .segments |
| .push(Ident::new("serialize", Span::call_site()).into()); |
| serialize_with.set(&meta.path, ser_path); |
| let mut de_path = path; |
| de_path |
| .path |
| .segments |
| .push(Ident::new("deserialize", Span::call_site()).into()); |
| deserialize_with.set(&meta.path, de_path); |
| } |
| } else if meta.path == BOUND { |
| // #[serde(bound = "T: SomeBound")] |
| // #[serde(bound(serialize = "...", deserialize = "..."))] |
| let (ser, de) = get_where_predicates(cx, &meta)?; |
| ser_bound.set_opt(&meta.path, ser); |
| de_bound.set_opt(&meta.path, de); |
| } else if meta.path == BORROW { |
| if meta.input.peek(Token![=]) { |
| // #[serde(borrow = "'a + 'b")] |
| let lifetimes = parse_lit_into_lifetimes(cx, &meta)?; |
| if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, field) { |
| for lifetime in &lifetimes { |
| if !borrowable.contains(lifetime) { |
| let msg = format!( |
| "field `{}` does not have lifetime {}", |
| ident, lifetime, |
| ); |
| cx.error_spanned_by(field, msg); |
| } |
| } |
| borrowed_lifetimes.set(&meta.path, lifetimes); |
| } |
| } else { |
| // #[serde(borrow)] |
| if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, field) { |
| borrowed_lifetimes.set(&meta.path, borrowable); |
| } |
| } |
| } else if meta.path == GETTER { |
| // #[serde(getter = "...")] |
| if let Some(path) = parse_lit_into_expr_path(cx, GETTER, &meta)? { |
| getter.set(&meta.path, path); |
| } |
| } else if meta.path == FLATTEN { |
| // #[serde(flatten)] |
| flatten.set_true(&meta.path); |
| } else { |
| let path = meta.path.to_token_stream().to_string().replace(' ', ""); |
| return Err( |
| meta.error(format_args!("unknown serde field attribute `{}`", path)) |
| ); |
| } |
| Ok(()) |
| }) { |
| cx.syn_error(err); |
| } |
| } |
| |
| // Is skip_deserializing, initialize the field to Default::default() unless a |
| // different default is specified by `#[serde(default = "...")]` on |
| // ourselves or our container (e.g. the struct we are in). |
| if let Default::None = *container_default { |
| if skip_deserializing.0.value.is_some() { |
| default.set_if_none(Default::Default); |
| } |
| } |
| |
| let mut borrowed_lifetimes = borrowed_lifetimes.get().unwrap_or_default(); |
| if !borrowed_lifetimes.is_empty() { |
| // Cow<str> and Cow<[u8]> never borrow by default: |
| // |
| // impl<'de, 'a, T: ?Sized> Deserialize<'de> for Cow<'a, T> |
| // |
| // A #[serde(borrow)] attribute enables borrowing that corresponds |
| // roughly to these impls: |
| // |
| // impl<'de: 'a, 'a> Deserialize<'de> for Cow<'a, str> |
| // impl<'de: 'a, 'a> Deserialize<'de> for Cow<'a, [u8]> |
| if is_cow(&field.ty, is_str) { |
| let mut path = syn::Path { |
| leading_colon: None, |
| segments: Punctuated::new(), |
| }; |
| let span = Span::call_site(); |
| path.segments.push(Ident::new("_serde", span).into()); |
| path.segments.push(Ident::new("__private", span).into()); |
| path.segments.push(Ident::new("de", span).into()); |
| path.segments |
| .push(Ident::new("borrow_cow_str", span).into()); |
| let expr = syn::ExprPath { |
| attrs: Vec::new(), |
| qself: None, |
| path, |
| }; |
| deserialize_with.set_if_none(expr); |
| } else if is_cow(&field.ty, is_slice_u8) { |
| let mut path = syn::Path { |
| leading_colon: None, |
| segments: Punctuated::new(), |
| }; |
| let span = Span::call_site(); |
| path.segments.push(Ident::new("_serde", span).into()); |
| path.segments.push(Ident::new("__private", span).into()); |
| path.segments.push(Ident::new("de", span).into()); |
| path.segments |
| .push(Ident::new("borrow_cow_bytes", span).into()); |
| let expr = syn::ExprPath { |
| attrs: Vec::new(), |
| qself: None, |
| path, |
| }; |
| deserialize_with.set_if_none(expr); |
| } |
| } else if is_implicitly_borrowed(&field.ty) { |
| // Types &str and &[u8] are always implicitly borrowed. No need for |
| // a #[serde(borrow)]. |
| collect_lifetimes(&field.ty, &mut borrowed_lifetimes); |
| } |
| |
| Field { |
| name: Name::from_attrs(ident, ser_name, de_name, Some(de_aliases)), |
| skip_serializing: skip_serializing.get(), |
| skip_deserializing: skip_deserializing.get(), |
| skip_serializing_if: skip_serializing_if.get(), |
| default: default.get().unwrap_or(Default::None), |
| serialize_with: serialize_with.get(), |
| deserialize_with: deserialize_with.get(), |
| ser_bound: ser_bound.get(), |
| de_bound: de_bound.get(), |
| borrowed_lifetimes, |
| getter: getter.get(), |
| flatten: flatten.get(), |
| transparent: false, |
| } |
| } |
| |
| pub fn name(&self) -> &Name { |
| &self.name |
| } |
| |
| pub fn aliases(&self) -> Vec<String> { |
| self.name.deserialize_aliases() |
| } |
| |
| pub fn rename_by_rules(&mut self, rules: &RenameAllRules) { |
| if !self.name.serialize_renamed { |
| self.name.serialize = rules.serialize.apply_to_field(&self.name.serialize); |
| } |
| if !self.name.deserialize_renamed { |
| self.name.deserialize = rules.deserialize.apply_to_field(&self.name.deserialize); |
| } |
| } |
| |
| pub fn skip_serializing(&self) -> bool { |
| self.skip_serializing |
| } |
| |
| pub fn skip_deserializing(&self) -> bool { |
| self.skip_deserializing |
| } |
| |
| pub fn skip_serializing_if(&self) -> Option<&syn::ExprPath> { |
| self.skip_serializing_if.as_ref() |
| } |
| |
| pub fn default(&self) -> &Default { |
| &self.default |
| } |
| |
| pub fn serialize_with(&self) -> Option<&syn::ExprPath> { |
| self.serialize_with.as_ref() |
| } |
| |
| pub fn deserialize_with(&self) -> Option<&syn::ExprPath> { |
| self.deserialize_with.as_ref() |
| } |
| |
| pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> { |
| self.ser_bound.as_ref().map(|vec| &vec[..]) |
| } |
| |
| pub fn de_bound(&self) -> Option<&[syn::WherePredicate]> { |
| self.de_bound.as_ref().map(|vec| &vec[..]) |
| } |
| |
| pub fn borrowed_lifetimes(&self) -> &BTreeSet<syn::Lifetime> { |
| &self.borrowed_lifetimes |
| } |
| |
| pub fn getter(&self) -> Option<&syn::ExprPath> { |
| self.getter.as_ref() |
| } |
| |
| pub fn flatten(&self) -> bool { |
| self.flatten |
| } |
| |
| pub fn transparent(&self) -> bool { |
| self.transparent |
| } |
| |
| pub fn mark_transparent(&mut self) { |
| self.transparent = true; |
| } |
| } |
| |
| type SerAndDe<T> = (Option<T>, Option<T>); |
| |
| fn get_ser_and_de<'c, T, F, R>( |
| cx: &'c Ctxt, |
| attr_name: Symbol, |
| meta: &ParseNestedMeta, |
| f: F, |
| ) -> syn::Result<(VecAttr<'c, T>, VecAttr<'c, T>)> |
| where |
| T: Clone, |
| F: Fn(&Ctxt, Symbol, Symbol, &ParseNestedMeta) -> syn::Result<R>, |
| R: Into<Option<T>>, |
| { |
| let mut ser_meta = VecAttr::none(cx, attr_name); |
| let mut de_meta = VecAttr::none(cx, attr_name); |
| |
| let lookahead = meta.input.lookahead1(); |
| if lookahead.peek(Token![=]) { |
| if let Some(both) = f(cx, attr_name, attr_name, meta)?.into() { |
| ser_meta.insert(&meta.path, both.clone()); |
| de_meta.insert(&meta.path, both); |
| } |
| } else if lookahead.peek(token::Paren) { |
| meta.parse_nested_meta(|meta| { |
| if meta.path == SERIALIZE { |
| if let Some(v) = f(cx, attr_name, SERIALIZE, &meta)?.into() { |
| ser_meta.insert(&meta.path, v); |
| } |
| } else if meta.path == DESERIALIZE { |
| if let Some(v) = f(cx, attr_name, DESERIALIZE, &meta)?.into() { |
| de_meta.insert(&meta.path, v); |
| } |
| } else { |
| return Err(meta.error(format_args!( |
| "malformed {0} attribute, expected `{0}(serialize = ..., deserialize = ...)`", |
| attr_name, |
| ))); |
| } |
| Ok(()) |
| })?; |
| } else { |
| return Err(lookahead.error()); |
| } |
| |
| Ok((ser_meta, de_meta)) |
| } |
| |
| fn get_renames( |
| cx: &Ctxt, |
| attr_name: Symbol, |
| meta: &ParseNestedMeta, |
| ) -> syn::Result<SerAndDe<syn::LitStr>> { |
| let (ser, de) = get_ser_and_de(cx, attr_name, meta, get_lit_str2)?; |
| Ok((ser.at_most_one(), de.at_most_one())) |
| } |
| |
| fn get_multiple_renames( |
| cx: &Ctxt, |
| meta: &ParseNestedMeta, |
| ) -> syn::Result<(Option<syn::LitStr>, Vec<syn::LitStr>)> { |
| let (ser, de) = get_ser_and_de(cx, RENAME, meta, get_lit_str2)?; |
| Ok((ser.at_most_one(), de.get())) |
| } |
| |
| fn get_where_predicates( |
| cx: &Ctxt, |
| meta: &ParseNestedMeta, |
| ) -> syn::Result<SerAndDe<Vec<syn::WherePredicate>>> { |
| let (ser, de) = get_ser_and_de(cx, BOUND, meta, parse_lit_into_where)?; |
| Ok((ser.at_most_one(), de.at_most_one())) |
| } |
| |
| fn get_lit_str( |
| cx: &Ctxt, |
| attr_name: Symbol, |
| meta: &ParseNestedMeta, |
| ) -> syn::Result<Option<syn::LitStr>> { |
| get_lit_str2(cx, attr_name, attr_name, meta) |
| } |
| |
| fn get_lit_str2( |
| cx: &Ctxt, |
| attr_name: Symbol, |
| meta_item_name: Symbol, |
| meta: &ParseNestedMeta, |
| ) -> syn::Result<Option<syn::LitStr>> { |
| let expr: syn::Expr = meta.value()?.parse()?; |
| let mut value = &expr; |
| while let syn::Expr::Group(e) = value { |
| value = &e.expr; |
| } |
| if let syn::Expr::Lit(syn::ExprLit { |
| lit: syn::Lit::Str(lit), |
| .. |
| }) = value |
| { |
| Ok(Some(lit.clone())) |
| } else { |
| cx.error_spanned_by( |
| expr, |
| format!( |
| "expected serde {} attribute to be a string: `{} = \"...\"`", |
| attr_name, meta_item_name |
| ), |
| ); |
| Ok(None) |
| } |
| } |
| |
| fn parse_lit_into_path( |
| cx: &Ctxt, |
| attr_name: Symbol, |
| meta: &ParseNestedMeta, |
| ) -> syn::Result<Option<syn::Path>> { |
| let string = match get_lit_str(cx, attr_name, meta)? { |
| Some(string) => string, |
| None => return Ok(None), |
| }; |
| |
| Ok(match string.parse() { |
| Ok(path) => Some(path), |
| Err(_) => { |
| cx.error_spanned_by( |
| &string, |
| format!("failed to parse path: {:?}", string.value()), |
| ); |
| None |
| } |
| }) |
| } |
| |
| fn parse_lit_into_expr_path( |
| cx: &Ctxt, |
| attr_name: Symbol, |
| meta: &ParseNestedMeta, |
| ) -> syn::Result<Option<syn::ExprPath>> { |
| let string = match get_lit_str(cx, attr_name, meta)? { |
| Some(string) => string, |
| None => return Ok(None), |
| }; |
| |
| Ok(match string.parse() { |
| Ok(expr) => Some(expr), |
| Err(_) => { |
| cx.error_spanned_by( |
| &string, |
| format!("failed to parse path: {:?}", string.value()), |
| ); |
| None |
| } |
| }) |
| } |
| |
| fn parse_lit_into_where( |
| cx: &Ctxt, |
| attr_name: Symbol, |
| meta_item_name: Symbol, |
| meta: &ParseNestedMeta, |
| ) -> syn::Result<Vec<syn::WherePredicate>> { |
| let string = match get_lit_str2(cx, attr_name, meta_item_name, meta)? { |
| Some(string) => string, |
| None => return Ok(Vec::new()), |
| }; |
| |
| Ok( |
| match string.parse_with(Punctuated::<syn::WherePredicate, Token![,]>::parse_terminated) { |
| Ok(predicates) => Vec::from_iter(predicates), |
| Err(err) => { |
| cx.error_spanned_by(string, err); |
| Vec::new() |
| } |
| }, |
| ) |
| } |
| |
| fn parse_lit_into_ty( |
| cx: &Ctxt, |
| attr_name: Symbol, |
| meta: &ParseNestedMeta, |
| ) -> syn::Result<Option<syn::Type>> { |
| let string = match get_lit_str(cx, attr_name, meta)? { |
| Some(string) => string, |
| None => return Ok(None), |
| }; |
| |
| Ok(match string.parse() { |
| Ok(ty) => Some(ty), |
| Err(_) => { |
| cx.error_spanned_by( |
| &string, |
| format!("failed to parse type: {} = {:?}", attr_name, string.value()), |
| ); |
| None |
| } |
| }) |
| } |
| |
| // Parses a string literal like "'a + 'b + 'c" containing a nonempty list of |
| // lifetimes separated by `+`. |
| fn parse_lit_into_lifetimes( |
| cx: &Ctxt, |
| meta: &ParseNestedMeta, |
| ) -> syn::Result<BTreeSet<syn::Lifetime>> { |
| let string = match get_lit_str(cx, BORROW, meta)? { |
| Some(string) => string, |
| None => return Ok(BTreeSet::new()), |
| }; |
| |
| if let Ok(lifetimes) = string.parse_with(|input: ParseStream| { |
| let mut set = BTreeSet::new(); |
| while !input.is_empty() { |
| let lifetime: Lifetime = input.parse()?; |
| if !set.insert(lifetime.clone()) { |
| cx.error_spanned_by( |
| &string, |
| format!("duplicate borrowed lifetime `{}`", lifetime), |
| ); |
| } |
| if input.is_empty() { |
| break; |
| } |
| input.parse::<Token![+]>()?; |
| } |
| Ok(set) |
| }) { |
| if lifetimes.is_empty() { |
| cx.error_spanned_by(string, "at least one lifetime must be borrowed"); |
| } |
| return Ok(lifetimes); |
| } |
| |
| cx.error_spanned_by( |
| &string, |
| format!("failed to parse borrowed lifetimes: {:?}", string.value()), |
| ); |
| Ok(BTreeSet::new()) |
| } |
| |
| fn is_implicitly_borrowed(ty: &syn::Type) -> bool { |
| is_implicitly_borrowed_reference(ty) || is_option(ty, is_implicitly_borrowed_reference) |
| } |
| |
| fn is_implicitly_borrowed_reference(ty: &syn::Type) -> bool { |
| is_reference(ty, is_str) || is_reference(ty, is_slice_u8) |
| } |
| |
| // Whether the type looks like it might be `std::borrow::Cow<T>` where elem="T". |
| // This can have false negatives and false positives. |
| // |
| // False negative: |
| // |
| // use std::borrow::Cow as Pig; |
| // |
| // #[derive(Deserialize)] |
| // struct S<'a> { |
| // #[serde(borrow)] |
| // pig: Pig<'a, str>, |
| // } |
| // |
| // False positive: |
| // |
| // type str = [i16]; |
| // |
| // #[derive(Deserialize)] |
| // struct S<'a> { |
| // #[serde(borrow)] |
| // cow: Cow<'a, str>, |
| // } |
| fn is_cow(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { |
| let path = match ungroup(ty) { |
| syn::Type::Path(ty) => &ty.path, |
| _ => { |
| return false; |
| } |
| }; |
| let seg = match path.segments.last() { |
| Some(seg) => seg, |
| None => { |
| return false; |
| } |
| }; |
| let args = match &seg.arguments { |
| syn::PathArguments::AngleBracketed(bracketed) => &bracketed.args, |
| _ => { |
| return false; |
| } |
| }; |
| seg.ident == "Cow" |
| && args.len() == 2 |
| && match (&args[0], &args[1]) { |
| (syn::GenericArgument::Lifetime(_), syn::GenericArgument::Type(arg)) => elem(arg), |
| _ => false, |
| } |
| } |
| |
| fn is_option(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { |
| let path = match ungroup(ty) { |
| syn::Type::Path(ty) => &ty.path, |
| _ => { |
| return false; |
| } |
| }; |
| let seg = match path.segments.last() { |
| Some(seg) => seg, |
| None => { |
| return false; |
| } |
| }; |
| let args = match &seg.arguments { |
| syn::PathArguments::AngleBracketed(bracketed) => &bracketed.args, |
| _ => { |
| return false; |
| } |
| }; |
| seg.ident == "Option" |
| && args.len() == 1 |
| && match &args[0] { |
| syn::GenericArgument::Type(arg) => elem(arg), |
| _ => false, |
| } |
| } |
| |
| // Whether the type looks like it might be `&T` where elem="T". This can have |
| // false negatives and false positives. |
| // |
| // False negative: |
| // |
| // type Yarn = str; |
| // |
| // #[derive(Deserialize)] |
| // struct S<'a> { |
| // r: &'a Yarn, |
| // } |
| // |
| // False positive: |
| // |
| // type str = [i16]; |
| // |
| // #[derive(Deserialize)] |
| // struct S<'a> { |
| // r: &'a str, |
| // } |
| fn is_reference(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { |
| match ungroup(ty) { |
| syn::Type::Reference(ty) => ty.mutability.is_none() && elem(&ty.elem), |
| _ => false, |
| } |
| } |
| |
| fn is_str(ty: &syn::Type) -> bool { |
| is_primitive_type(ty, "str") |
| } |
| |
| fn is_slice_u8(ty: &syn::Type) -> bool { |
| match ungroup(ty) { |
| syn::Type::Slice(ty) => is_primitive_type(&ty.elem, "u8"), |
| _ => false, |
| } |
| } |
| |
| fn is_primitive_type(ty: &syn::Type, primitive: &str) -> bool { |
| match ungroup(ty) { |
| syn::Type::Path(ty) => ty.qself.is_none() && is_primitive_path(&ty.path, primitive), |
| _ => false, |
| } |
| } |
| |
| fn is_primitive_path(path: &syn::Path, primitive: &str) -> bool { |
| path.leading_colon.is_none() |
| && path.segments.len() == 1 |
| && path.segments[0].ident == primitive |
| && path.segments[0].arguments.is_empty() |
| } |
| |
| // All lifetimes that this type could borrow from a Deserializer. |
| // |
| // For example a type `S<'a, 'b>` could borrow `'a` and `'b`. On the other hand |
| // a type `for<'a> fn(&'a str)` could not borrow `'a` from the Deserializer. |
| // |
| // This is used when there is an explicit or implicit `#[serde(borrow)]` |
| // attribute on the field so there must be at least one borrowable lifetime. |
| fn borrowable_lifetimes( |
| cx: &Ctxt, |
| name: &str, |
| field: &syn::Field, |
| ) -> Result<BTreeSet<syn::Lifetime>, ()> { |
| let mut lifetimes = BTreeSet::new(); |
| collect_lifetimes(&field.ty, &mut lifetimes); |
| if lifetimes.is_empty() { |
| let msg = format!("field `{}` has no lifetimes to borrow", name); |
| cx.error_spanned_by(field, msg); |
| Err(()) |
| } else { |
| Ok(lifetimes) |
| } |
| } |
| |
| fn collect_lifetimes(ty: &syn::Type, out: &mut BTreeSet<syn::Lifetime>) { |
| match ty { |
| syn::Type::Slice(ty) => { |
| collect_lifetimes(&ty.elem, out); |
| } |
| syn::Type::Array(ty) => { |
| collect_lifetimes(&ty.elem, out); |
| } |
| syn::Type::Ptr(ty) => { |
| collect_lifetimes(&ty.elem, out); |
| } |
| syn::Type::Reference(ty) => { |
| out.extend(ty.lifetime.iter().cloned()); |
| collect_lifetimes(&ty.elem, out); |
| } |
| syn::Type::Tuple(ty) => { |
| for elem in &ty.elems { |
| collect_lifetimes(elem, out); |
| } |
| } |
| syn::Type::Path(ty) => { |
| if let Some(qself) = &ty.qself { |
| collect_lifetimes(&qself.ty, out); |
| } |
| for seg in &ty.path.segments { |
| if let syn::PathArguments::AngleBracketed(bracketed) = &seg.arguments { |
| for arg in &bracketed.args { |
| match arg { |
| syn::GenericArgument::Lifetime(lifetime) => { |
| out.insert(lifetime.clone()); |
| } |
| syn::GenericArgument::Type(ty) => { |
| collect_lifetimes(ty, out); |
| } |
| syn::GenericArgument::AssocType(binding) => { |
| collect_lifetimes(&binding.ty, out); |
| } |
| _ => {} |
| } |
| } |
| } |
| } |
| } |
| syn::Type::Paren(ty) => { |
| collect_lifetimes(&ty.elem, out); |
| } |
| syn::Type::Group(ty) => { |
| collect_lifetimes(&ty.elem, out); |
| } |
| syn::Type::Macro(ty) => { |
| collect_lifetimes_from_tokens(ty.mac.tokens.clone(), out); |
| } |
| syn::Type::BareFn(_) |
| | syn::Type::Never(_) |
| | syn::Type::TraitObject(_) |
| | syn::Type::ImplTrait(_) |
| | syn::Type::Infer(_) |
| | syn::Type::Verbatim(_) => {} |
| |
| #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] |
| _ => {} |
| } |
| } |
| |
| fn collect_lifetimes_from_tokens(tokens: TokenStream, out: &mut BTreeSet<syn::Lifetime>) { |
| let mut iter = tokens.into_iter(); |
| while let Some(tt) = iter.next() { |
| match &tt { |
| TokenTree::Punct(op) if op.as_char() == '\'' && op.spacing() == Spacing::Joint => { |
| if let Some(TokenTree::Ident(ident)) = iter.next() { |
| out.insert(syn::Lifetime { |
| apostrophe: op.span(), |
| ident, |
| }); |
| } |
| } |
| TokenTree::Group(group) => { |
| let tokens = group.stream(); |
| collect_lifetimes_from_tokens(tokens, out); |
| } |
| _ => {} |
| } |
| } |
| } |