use crate::internals::symbol::*; use crate::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::meta::ParseNestedMeta; use syn::parse::ParseStream; use syn::punctuated::Punctuated; use syn::{parse_quote, token, Ident, Lifetime, Token}; // 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 crate::internals::case::RenameRule; struct Attr<'c, T> { cx: &'c Ctxt, name: Symbol, tokens: TokenStream, value: Option, } impl<'c, T> Attr<'c, T> { fn none(cx: &'c Ctxt, name: Symbol) -> Self { Attr { cx, name, tokens: TokenStream::new(), value: None, } } fn set(&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(&mut self, obj: A, value: Option) { 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 { 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(&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, } 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(&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 { 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 { self.values } } pub struct Name { serialize: String, serialize_renamed: bool, deserialize: String, deserialize_renamed: bool, deserialize_aliases: BTreeSet, } 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, de_name: Attr, de_aliases: Option>, ) -> Name { let mut alias_set = BTreeSet::new(); if let Some(de_aliases) = de_aliases { for alias_name in de_aliases.get() { alias_set.insert(alias_name); } } 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: alias_set, } } /// Return the container name for the container when serializing. pub fn serialize_name(&self) -> &str { &self.serialize } /// Return the container name for the container when deserializing. pub fn deserialize_name(&self) -> &str { &self.deserialize } fn deserialize_aliases(&self) -> &BTreeSet { &self.deserialize_aliases } } #[derive(Copy, Clone)] pub struct RenameAllRules { serialize: RenameRule, deserialize: RenameRule, } impl RenameAllRules { /// Returns a new `RenameAllRules` with the individual rules of `self` and /// `other_rules` joined by `RenameRules::or`. pub fn or(self, other_rules: Self) -> Self { Self { serialize: self.serialize.or(other_rules.serialize), deserialize: self.deserialize.or(other_rules.deserialize), } } } /// Represents struct or enum attribute information. pub struct Container { name: Name, transparent: bool, deny_unknown_fields: bool, default: Default, rename_all_rules: RenameAllRules, rename_all_fields_rules: RenameAllRules, ser_bound: Option>, de_bound: Option>, tag: TagType, type_from: Option, type_try_from: Option, type_into: Option, remote: Option, identifier: Identifier, has_flatten: bool, serde_path: Option, is_packed: bool, /// Error message generated when type can't be deserialized expecting: Option, non_exhaustive: bool, } /// 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 rename_all_fields_ser_rule = Attr::none(cx, RENAME_ALL_FIELDS); let mut rename_all_fields_de_rule = Attr::none(cx, RENAME_ALL_FIELDS); 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); let mut non_exhaustive = false; for attr in &item.attrs { if attr.path() != SERDE { non_exhaustive |= matches!(&attr.meta, syn::Meta::Path(path) if path == NON_EXHAUSTIVE); continue; } if let syn::Meta::List(meta) = &attr.meta { if meta.tokens.is_empty() { 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 == RENAME_ALL_FIELDS { // #[serde(rename_all_fields = "foo")] // #[serde(rename_all_fields(serialize = "foo", deserialize = "bar"))] let one_name = meta.input.peek(Token![=]); let (ser, de) = get_renames(cx, RENAME_ALL_FIELDS, &meta)?; match item.data { syn::Data::Enum(_) => { if let Some(ser) = ser { match RenameRule::from_str(&ser.value()) { Ok(rename_rule) => { rename_all_fields_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_fields_de_rule.set(&meta.path, rename_rule); } Err(err) => { if !one_name { cx.error_spanned_by(de, err); } } } } } syn::Data::Struct(_) => { let msg = "#[serde(rename_all_fields)] can only be used on enums"; cx.syn_error(meta.error(msg)); } syn::Data::Union(_) => { let msg = "#[serde(rename_all_fields)] can only be used on enums"; cx.syn_error(meta.error(msg)); } } } 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(_) | syn::Fields::Unnamed(_) => { default.set(&meta.path, Default::Path(path)); } syn::Fields::Unit => { let msg = "#[serde(default = \"...\")] can only be used on structs that have fields"; cx.syn_error(meta.error(msg)); } }, syn::Data::Enum(_) => { let msg = "#[serde(default = \"...\")] can only be used on structs"; cx.syn_error(meta.error(msg)); } syn::Data::Union(_) => { let msg = "#[serde(default = \"...\")] can only be used on structs"; cx.syn_error(meta.error(msg)); } } } } else { // #[serde(default)] match &item.data { syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields { syn::Fields::Named(_) | syn::Fields::Unnamed(_) => { default.set(meta.path, Default::Default); } syn::Fields::Unit => { let msg = "#[serde(default)] can only be used on structs that have fields"; cx.error_spanned_by(fields, msg); } }, syn::Data::Enum(_) => { let msg = "#[serde(default)] can only be used on structs"; cx.syn_error(meta.error(msg)); } syn::Data::Union(_) => { let msg = "#[serde(default)] can only be used on structs"; cx.syn_error(meta.error(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(_) => { let msg = "#[serde(untagged)] can only be used on enums"; cx.syn_error(meta.error(msg)); } syn::Data::Union(_) => { let msg = "#[serde(untagged)] can only be used on enums"; cx.syn_error(meta.error(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.syn_error(meta.error(msg)); } }, syn::Data::Union(_) => { let msg = "#[serde(tag = \"...\")] can only be used on enums and structs with named fields"; cx.syn_error(meta.error(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(_) => { let msg = "#[serde(content = \"...\")] can only be used on enums"; cx.syn_error(meta.error(msg)); } syn::Data::Union(_) => { let msg = "#[serde(content = \"...\")] can only be used on enums"; cx.syn_error(meta.error(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), }, rename_all_fields_rules: RenameAllRules { serialize: rename_all_fields_ser_rule.get().unwrap_or(RenameRule::None), deserialize: rename_all_fields_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(), non_exhaustive, } } pub fn name(&self) -> &Name { &self.name } pub fn rename_all_rules(&self) -> RenameAllRules { self.rename_all_rules } pub fn rename_all_fields_rules(&self) -> RenameAllRules { self.rename_all_fields_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 { 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) } pub fn non_exhaustive(&self) -> bool { self.non_exhaustive } } fn decide_tag( cx: &Ctxt, item: &syn::DeriveInput, untagged: BoolAttr, internal_tag: Attr, content: Attr, ) -> 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>, de_bound: Option>, skip_deserializing: bool, skip_serializing: bool, other: bool, serialize_with: Option, deserialize_with: Option, borrow: Option, untagged: bool, } struct BorrowAttribute { path: syn::Path, lifetimes: Option>, } 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); let mut untagged = BoolAttr::none(cx, UNTAGGED); for attr in &variant.attrs { if attr.path() != SERDE { continue; } if let syn::Meta::List(meta) = &attr.meta { if meta.tokens.is_empty() { 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 if meta.path == UNTAGGED { untagged.set_true(&meta.path); } 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(), untagged: untagged.get(), } } pub fn name(&self) -> &Name { &self.name } pub fn aliases(&self) -> &BTreeSet { 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); } self.name .deserialize_aliases .insert(self.name.deserialize.clone()); } 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() } pub fn untagged(&self) -> bool { self.untagged } } /// Represents field attribute information pub struct Field { name: Name, skip_serializing: bool, skip_deserializing: bool, skip_serializing_if: Option, default: Default, serialize_with: Option, deserialize_with: Option, ser_bound: Option>, de_bound: Option>, borrowed_lifetimes: BTreeSet, getter: Option, 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 syn::Meta::List(meta) = &attr.meta { if meta.tokens.is_empty() { 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 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) -> &BTreeSet { 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); } self.name .deserialize_aliases .insert(self.name.deserialize.clone()); } 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 { &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 = (Option, Option); 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: Into>, { 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> { 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, Vec)> { 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>> { 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> { 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> { 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 { let suffix = lit.suffix(); if !suffix.is_empty() { cx.error_spanned_by( lit, format!("unexpected suffix `{}` on string literal", suffix), ); } 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> { 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> { 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> { 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::::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> { 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> { 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::()?; } 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` 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, ()> { 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) { match ty { #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] 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::GenericArgument::Const(_) | syn::GenericArgument::AssocConst(_) | syn::GenericArgument::Constraint(_) | _ => {} } } } } } 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(_) => {} _ => {} } } fn collect_lifetimes_from_tokens(tokens: TokenStream, out: &mut BTreeSet) { 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); } _ => {} } } }