use Ctxt; use syn; use syn::MetaItem::{List, NameValue, Word}; use syn::NestedMetaItem::{Literal, MetaItem}; use synom::IResult; use std::collections::BTreeSet; use std::str::FromStr; // This module handles parsing of `#[serde(...)]` attributes. The entrypoints // are `attr::Item::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 case::RenameRule; struct Attr<'c, T> { cx: &'c Ctxt, name: &'static str, value: Option, } impl<'c, T> Attr<'c, T> { fn none(cx: &'c Ctxt, name: &'static str) -> Self { Attr { cx: cx, name: name, value: None, } } fn set(&mut self, value: T) { if self.value.is_some() { self.cx.error(format!("duplicate serde attribute `{}`", self.name)); } else { self.value = Some(value); } } fn set_opt(&mut self, value: Option) { if let Some(value) = value { self.set(value); } } fn set_if_none(&mut self, value: T) { if self.value.is_none() { self.value = Some(value); } } fn get(self) -> Option { self.value } } struct BoolAttr<'c>(Attr<'c, ()>); impl<'c> BoolAttr<'c> { fn none(cx: &'c Ctxt, name: &'static str) -> Self { BoolAttr(Attr::none(cx, name)) } fn set_true(&mut self) { self.0.set(()); } fn get(&self) -> bool { self.0.value.is_some() } } #[derive(Debug)] pub struct Name { serialize: String, deserialize: String, } impl Name { /// 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() } } /// Represents container (e.g. struct) attribute information #[derive(Debug)] pub struct Item { name: Name, deny_unknown_fields: bool, default: Default, rename_all: RenameRule, ser_bound: Option>, de_bound: Option>, tag: EnumTag, from_type: Option, into_type: Option, } /// Styles of representing an enum. #[derive(Debug)] pub enum EnumTag { /// 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, } impl Item { /// Extract out the `#[serde(...)]` attributes from an item. pub fn from_ast(cx: &Ctxt, item: &syn::MacroInput) -> Self { let mut ser_name = Attr::none(cx, "rename"); let mut de_name = Attr::none(cx, "rename"); let mut deny_unknown_fields = BoolAttr::none(cx, "deny_unknown_fields"); let mut default = Attr::none(cx, "default"); let mut rename_all = 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 from_type = Attr::none(cx, "from"); let mut into_type = Attr::none(cx, "into"); for meta_items in item.attrs.iter().filter_map(get_serde_meta_items) { for meta_item in meta_items { match meta_item { // Parse `#[serde(rename="foo")]` MetaItem(NameValue(ref name, ref lit)) if name == "rename" => { if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) { ser_name.set(s.clone()); de_name.set(s); } } // Parse `#[serde(rename(serialize="foo", deserialize="bar"))]` MetaItem(List(ref name, ref meta_items)) if name == "rename" => { if let Ok((ser, de)) = get_renames(cx, meta_items) { ser_name.set_opt(ser); de_name.set_opt(de); } } // Parse `#[serde(rename_all="foo")]` MetaItem(NameValue(ref name, ref lit)) if name == "rename_all" => { if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) { match RenameRule::from_str(&s) { Ok(rename_rule) => rename_all.set(rename_rule), Err(()) => { cx.error(format!("unknown rename rule for #[serde(rename_all \ = {:?})]", s)) } } } } // Parse `#[serde(deny_unknown_fields)]` MetaItem(Word(ref name)) if name == "deny_unknown_fields" => { deny_unknown_fields.set_true(); } // Parse `#[serde(default)]` MetaItem(Word(ref name)) if name == "default" => { match item.body { syn::Body::Struct(syn::VariantData::Struct(_)) => { default.set(Default::Default); } _ => { cx.error("#[serde(default)] can only be used on structs \ with named fields") } } } // Parse `#[serde(default="...")]` MetaItem(NameValue(ref name, ref lit)) if name == "default" => { if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { match item.body { syn::Body::Struct(syn::VariantData::Struct(_)) => { default.set(Default::Path(path)); } _ => { cx.error("#[serde(default = \"...\")] can only be used \ on structs with named fields") } } } } // Parse `#[serde(bound="D: Serialize")]` MetaItem(NameValue(ref name, ref lit)) if name == "bound" => { if let Ok(where_predicates) = parse_lit_into_where(cx, name.as_ref(), name.as_ref(), lit) { ser_bound.set(where_predicates.clone()); de_bound.set(where_predicates); } } // Parse `#[serde(bound(serialize="D: Serialize", deserialize="D: Deserialize"))]` MetaItem(List(ref name, ref meta_items)) if name == "bound" => { if let Ok((ser, de)) = get_where_predicates(cx, meta_items) { ser_bound.set_opt(ser); de_bound.set_opt(de); } } // Parse `#[serde(untagged)]` MetaItem(Word(ref name)) if name == "untagged" => { match item.body { syn::Body::Enum(_) => { untagged.set_true(); } syn::Body::Struct(_) => { cx.error("#[serde(untagged)] can only be used on enums") } } } // Parse `#[serde(tag = "type")]` MetaItem(NameValue(ref name, ref lit)) if name == "tag" => { if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) { match item.body { syn::Body::Enum(_) => { internal_tag.set(s); } syn::Body::Struct(_) => { cx.error("#[serde(tag = \"...\")] can only be used on enums") } } } } // Parse `#[serde(content = "c")]` MetaItem(NameValue(ref name, ref lit)) if name == "content" => { if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) { match item.body { syn::Body::Enum(_) => { content.set(s); } syn::Body::Struct(_) => { cx.error("#[serde(content = \"...\")] can only be used on \ enums") } } } } // Parse `#[serde(from = "Type")] MetaItem(NameValue(ref name, ref lit)) if name == "from" => { if let Ok(from_ty) = parse_lit_into_ty(cx, name.as_ref(), lit) { from_type.set_opt(Some(from_ty)); } } // Parse `#[serde(into = "Type")] MetaItem(NameValue(ref name, ref lit)) if name == "into" => { if let Ok(into_ty) = parse_lit_into_ty(cx, name.as_ref(), lit) { into_type.set_opt(Some(into_ty)); } } MetaItem(ref meta_item) => { cx.error(format!("unknown serde container attribute `{}`", meta_item.name())); } Literal(_) => { cx.error("unexpected literal in serde container attribute"); } } } } let tag = match (untagged.get(), internal_tag.get(), content.get()) { (false, None, None) => EnumTag::External, (true, None, None) => EnumTag::None, (false, Some(tag), None) => { // Check that there are no tuple variants. if let syn::Body::Enum(ref variants) = item.body { for variant in variants { match variant.data { syn::VariantData::Struct(_) | syn::VariantData::Unit => {} syn::VariantData::Tuple(ref fields) => { if fields.len() != 1 { cx.error("#[serde(tag = \"...\")] cannot be used with tuple \ variants"); break; } } } } } EnumTag::Internal { tag: tag } } (true, Some(_), None) => { cx.error("enum cannot be both untagged and internally tagged"); EnumTag::External // doesn't matter, will error } (false, None, Some(_)) => { cx.error("#[serde(tag = \"...\", content = \"...\")] must be used together"); EnumTag::External } (true, None, Some(_)) => { cx.error("untagged enum cannot have #[serde(content = \"...\")]"); EnumTag::External } (false, Some(tag), Some(content)) => { EnumTag::Adjacent { tag: tag, content: content, } } (true, Some(_), Some(_)) => { cx.error("untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]"); EnumTag::External } }; Item { name: Name { serialize: ser_name.get().unwrap_or_else(|| item.ident.to_string()), deserialize: de_name.get().unwrap_or_else(|| item.ident.to_string()), }, deny_unknown_fields: deny_unknown_fields.get(), default: default.get().unwrap_or(Default::None), rename_all: rename_all.get().unwrap_or(RenameRule::None), ser_bound: ser_bound.get(), de_bound: de_bound.get(), tag: tag, from_type: from_type.get(), into_type: into_type.get(), } } pub fn name(&self) -> &Name { &self.name } pub fn rename_all(&self) -> &RenameRule { &self.rename_all } 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) -> &EnumTag { &self.tag } pub fn from_type(&self) -> Option<&syn::Ty> { self.from_type.as_ref() } pub fn into_type(&self) -> Option<&syn::Ty> { self.into_type.as_ref() } } /// Represents variant attribute information #[derive(Debug)] pub struct Variant { name: Name, ser_renamed: bool, de_renamed: bool, rename_all: RenameRule, skip_deserializing: bool, skip_serializing: bool, } 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 skip_deserializing = BoolAttr::none(cx, "skip_deserializing"); let mut skip_serializing = BoolAttr::none(cx, "skip_serializing"); let mut rename_all = Attr::none(cx, "rename_all"); for meta_items in variant.attrs.iter().filter_map(get_serde_meta_items) { for meta_item in meta_items { match meta_item { // Parse `#[serde(rename="foo")]` MetaItem(NameValue(ref name, ref lit)) if name == "rename" => { if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) { ser_name.set(s.clone()); de_name.set(s); } } // Parse `#[serde(rename(serialize="foo", deserialize="bar"))]` MetaItem(List(ref name, ref meta_items)) if name == "rename" => { if let Ok((ser, de)) = get_renames(cx, meta_items) { ser_name.set_opt(ser); de_name.set_opt(de); } } // Parse `#[serde(rename_all="foo")]` MetaItem(NameValue(ref name, ref lit)) if name == "rename_all" => { if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) { match RenameRule::from_str(&s) { Ok(rename_rule) => rename_all.set(rename_rule), Err(()) => { cx.error(format!("unknown rename rule for #[serde(rename_all \ = {:?})]", s)) } } } } // Parse `#[serde(skip_deserializing)]` MetaItem(Word(ref name)) if name == "skip_deserializing" => { skip_deserializing.set_true(); } // Parse `#[serde(skip_serializing)]` MetaItem(Word(ref name)) if name == "skip_serializing" => { skip_serializing.set_true(); } MetaItem(ref meta_item) => { cx.error(format!("unknown serde variant attribute `{}`", meta_item.name())); } Literal(_) => { cx.error("unexpected literal in serde variant attribute"); } } } } 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(); Variant { name: Name { serialize: ser_name.unwrap_or_else(|| variant.ident.to_string()), deserialize: de_name.unwrap_or_else(|| variant.ident.to_string()), }, ser_renamed: ser_renamed, de_renamed: de_renamed, rename_all: rename_all.get().unwrap_or(RenameRule::None), skip_deserializing: skip_deserializing.get(), skip_serializing: skip_serializing.get(), } } pub fn name(&self) -> &Name { &self.name } pub fn rename_by_rule(&mut self, rule: &RenameRule) { if !self.ser_renamed { self.name.serialize = rule.apply_to_variant(&self.name.serialize); } if !self.de_renamed { self.name.deserialize = rule.apply_to_variant(&self.name.deserialize); } } pub fn rename_all(&self) -> &RenameRule { &self.rename_all } pub fn skip_deserializing(&self) -> bool { self.skip_deserializing } pub fn skip_serializing(&self) -> bool { self.skip_serializing } } /// Represents field attribute information #[derive(Debug)] pub struct Field { name: Name, ser_renamed: bool, de_renamed: bool, 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, } /// Represents the default to use for a field when deserializing. #[derive(Debug, PartialEq)] 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::Path), } impl Field { /// Extract out the `#[serde(...)]` attributes from a struct field. pub fn from_ast(cx: &Ctxt, index: usize, field: &syn::Field) -> Self { let mut ser_name = Attr::none(cx, "rename"); let mut de_name = Attr::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 ident = match field.ident { Some(ref ident) => ident.to_string(), None => index.to_string(), }; for meta_items in field.attrs.iter().filter_map(get_serde_meta_items) { for meta_item in meta_items { match meta_item { // Parse `#[serde(rename="foo")]` MetaItem(NameValue(ref name, ref lit)) if name == "rename" => { if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) { ser_name.set(s.clone()); de_name.set(s); } } // Parse `#[serde(rename(serialize="foo", deserialize="bar"))]` MetaItem(List(ref name, ref meta_items)) if name == "rename" => { if let Ok((ser, de)) = get_renames(cx, meta_items) { ser_name.set_opt(ser); de_name.set_opt(de); } } // Parse `#[serde(default)]` MetaItem(Word(ref name)) if name == "default" => { default.set(Default::Default); } // Parse `#[serde(default="...")]` MetaItem(NameValue(ref name, ref lit)) if name == "default" => { if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { default.set(Default::Path(path)); } } // Parse `#[serde(skip_serializing)]` MetaItem(Word(ref name)) if name == "skip_serializing" => { skip_serializing.set_true(); } // Parse `#[serde(skip_deserializing)]` MetaItem(Word(ref name)) if name == "skip_deserializing" => { skip_deserializing.set_true(); } // Parse `#[serde(skip_serializing_if="...")]` MetaItem(NameValue(ref name, ref lit)) if name == "skip_serializing_if" => { if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { skip_serializing_if.set(path); } } // Parse `#[serde(serialize_with="...")]` MetaItem(NameValue(ref name, ref lit)) if name == "serialize_with" => { if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { serialize_with.set(path); } } // Parse `#[serde(deserialize_with="...")]` MetaItem(NameValue(ref name, ref lit)) if name == "deserialize_with" => { if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { deserialize_with.set(path); } } // Parse `#[serde(with="...")]` MetaItem(NameValue(ref name, ref lit)) if name == "with" => { if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { let mut ser_path = path.clone(); ser_path.segments.push("serialize".into()); serialize_with.set(ser_path); let mut de_path = path; de_path.segments.push("deserialize".into()); deserialize_with.set(de_path); } } // Parse `#[serde(bound="D: Serialize")]` MetaItem(NameValue(ref name, ref lit)) if name == "bound" => { if let Ok(where_predicates) = parse_lit_into_where(cx, name.as_ref(), name.as_ref(), lit) { ser_bound.set(where_predicates.clone()); de_bound.set(where_predicates); } } // Parse `#[serde(bound(serialize="D: Serialize", deserialize="D: Deserialize"))]` MetaItem(List(ref name, ref meta_items)) if name == "bound" => { if let Ok((ser, de)) = get_where_predicates(cx, meta_items) { ser_bound.set_opt(ser); de_bound.set_opt(de); } } // Parse `#[serde(borrow)]` MetaItem(Word(ref name)) if name == "borrow" => { if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, &field.ty) { borrowed_lifetimes.set(borrowable); } } // Parse `#[serde(borrow = "'a + 'b")]` MetaItem(NameValue(ref name, ref lit)) if name == "borrow" => { if let Ok(lifetimes) = parse_lit_into_lifetimes(cx, name.as_ref(), lit) { if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, &field.ty) { for lifetime in &lifetimes { if !borrowable.contains(lifetime) { cx.error(format!("field `{}` does not have lifetime {}", ident, lifetime.ident)); } } borrowed_lifetimes.set(lifetimes); } } } MetaItem(ref meta_item) => { cx.error(format!("unknown serde field attribute `{}`", meta_item.name())); } Literal(_) => { cx.error("unexpected literal in serde field attribute"); } } } } // Is skip_deserializing, initialize the field to Default::default() // unless a different default is specified by `#[serde(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, "str") { let path = syn::parse_path("_serde::de::private::borrow_cow_str").unwrap(); deserialize_with.set_if_none(path); } else if is_cow(&field.ty, "[u8]") { let path = syn::parse_path("_serde::de::private::borrow_cow_bytes").unwrap(); deserialize_with.set_if_none(path); } } else if is_rptr(&field.ty, "str") || is_rptr(&field.ty, "[u8]") { // Types &str and &[u8] are always implicitly borrowed. No need for // a #[serde(borrow)]. borrowed_lifetimes = borrowable_lifetimes(cx, &ident, &field.ty).unwrap(); } 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(); Field { name: Name { serialize: ser_name.unwrap_or_else(|| ident.clone()), deserialize: de_name.unwrap_or(ident), }, ser_renamed: ser_renamed, de_renamed: de_renamed, 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: borrowed_lifetimes, } } pub fn name(&self) -> &Name { &self.name } pub fn rename_by_rule(&mut self, rule: &RenameRule) { if !self.ser_renamed { self.name.serialize = rule.apply_to_field(&self.name.serialize); } if !self.de_renamed { self.name.deserialize = rule.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::Path> { self.skip_serializing_if.as_ref() } pub fn default(&self) -> &Default { &self.default } pub fn serialize_with(&self) -> Option<&syn::Path> { self.serialize_with.as_ref() } pub fn deserialize_with(&self) -> Option<&syn::Path> { 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 } } type SerAndDe = (Option, Option); fn get_ser_and_de(cx: &Ctxt, attr_name: &'static str, items: &[syn::NestedMetaItem], f: F) -> Result, ()> where F: Fn(&Ctxt, &str, &str, &syn::Lit) -> Result { let mut ser_item = Attr::none(cx, attr_name); let mut de_item = Attr::none(cx, attr_name); for item in items { match *item { MetaItem(NameValue(ref name, ref lit)) if name == "serialize" => { if let Ok(v) = f(cx, attr_name, name.as_ref(), lit) { ser_item.set(v); } } MetaItem(NameValue(ref name, ref lit)) if name == "deserialize" => { if let Ok(v) = f(cx, attr_name, name.as_ref(), lit) { de_item.set(v); } } _ => { cx.error(format!("malformed {0} attribute, expected `{0}(serialize = ..., \ deserialize = ...)`", attr_name)); return Err(()); } } } Ok((ser_item.get(), de_item.get())) } fn get_renames(cx: &Ctxt, items: &[syn::NestedMetaItem]) -> Result, ()> { get_ser_and_de(cx, "rename", items, get_string_from_lit) } fn get_where_predicates(cx: &Ctxt, items: &[syn::NestedMetaItem]) -> Result>, ()> { get_ser_and_de(cx, "bound", items, parse_lit_into_where) } pub fn get_serde_meta_items(attr: &syn::Attribute) -> Option> { match attr.value { List(ref name, ref items) if name == "serde" => Some(items.iter().cloned().collect()), _ => None, } } fn get_string_from_lit(cx: &Ctxt, attr_name: &str, meta_item_name: &str, lit: &syn::Lit) -> Result { if let syn::Lit::Str(ref s, _) = *lit { Ok(s.clone()) } else { cx.error(format!("expected serde {} attribute to be a string: `{} = \"...\"`", attr_name, meta_item_name)); Err(()) } } fn parse_lit_into_path(cx: &Ctxt, attr_name: &str, lit: &syn::Lit) -> Result { let string = try!(get_string_from_lit(cx, attr_name, attr_name, lit)); syn::parse_path(&string).map_err(|err| cx.error(err)) } fn parse_lit_into_where(cx: &Ctxt, attr_name: &str, meta_item_name: &str, lit: &syn::Lit) -> Result, ()> { let string = try!(get_string_from_lit(cx, attr_name, meta_item_name, lit)); if string.is_empty() { return Ok(Vec::new()); } let where_string = format!("where {}", string); syn::parse_where_clause(&where_string).map(|wh| wh.predicates).map_err(|err| cx.error(err)) } fn parse_lit_into_ty(cx: &Ctxt, attr_name: &str, lit: &syn::Lit) -> Result { let string = try!(get_string_from_lit(cx, attr_name, attr_name, lit)); syn::parse_type(&string).map_err(|_| { cx.error(format!("failed to parse type: {} = {:?}", attr_name, string)) }) } // Parses a string literal like "'a + 'b + 'c" containing a nonempty list of // lifetimes separated by `+`. fn parse_lit_into_lifetimes(cx: &Ctxt, attr_name: &str, lit: &syn::Lit) -> Result, ()> { let string = try!(get_string_from_lit(cx, attr_name, attr_name, lit)); if string.is_empty() { cx.error("at least one lifetime must be borrowed"); return Err(()); } named!(lifetimes -> Vec, separated_nonempty_list!(punct!("+"), syn::parse::lifetime) ); if let IResult::Done(rest, o) = lifetimes(&string) { if rest.trim().is_empty() { let mut set = BTreeSet::new(); for lifetime in o { if !set.insert(lifetime.clone()) { cx.error(format!("duplicate borrowed lifetime `{}`", lifetime.ident)); } } return Ok(set); } } Err(cx.error(format!("failed to parse borrowed lifetimes: {:?}", string))) } // 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::Ty, elem: &str) -> bool { let path = match *ty { syn::Ty::Path(None, ref path) => path, _ => { return false; } }; let seg = match path.segments.last() { Some(seg) => seg, None => { return false; } }; let params = match seg.parameters { syn::PathParameters::AngleBracketed(ref params) => params, _ => { return false; } }; seg.ident == "Cow" && params.lifetimes.len() == 1 && params.types == vec![syn::parse_type(elem).unwrap()] && params.bindings.is_empty() } // 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_rptr(ty: &syn::Ty, elem: &str) -> bool { match *ty { syn::Ty::Rptr(Some(_), ref mut_ty) => { mut_ty.mutability == syn::Mutability::Immutable && mut_ty.ty == syn::parse_type(elem).unwrap() } _ => false, } } // 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, ty: &syn::Ty) -> Result, ()> { let mut lifetimes = BTreeSet::new(); collect_lifetimes(ty, &mut lifetimes); if lifetimes.is_empty() { Err(cx.error(format!("field `{}` has no lifetimes to borrow", name))) } else { Ok(lifetimes) } } fn collect_lifetimes(ty: &syn::Ty, out: &mut BTreeSet) { match *ty { syn::Ty::Slice(ref elem) | syn::Ty::Array(ref elem, _) | syn::Ty::Paren(ref elem) => { collect_lifetimes(elem, out); } syn::Ty::Ptr(ref elem) => { collect_lifetimes(&elem.ty, out); } syn::Ty::Rptr(ref lifetime, ref elem) => { out.extend(lifetime.iter().cloned()); collect_lifetimes(&elem.ty, out); } syn::Ty::Tup(ref elems) => { for elem in elems { collect_lifetimes(elem, out); } } syn::Ty::Path(ref qself, ref path) => { if let Some(ref qself) = *qself { collect_lifetimes(&qself.ty, out); } for seg in &path.segments { if let syn::PathParameters::AngleBracketed(ref params) = seg.parameters { out.extend(params.lifetimes.iter().cloned()); for ty in ¶ms.types { collect_lifetimes(ty, out); } for binding in ¶ms.bindings { collect_lifetimes(&binding.ty, out); } } } } syn::Ty::BareFn(_) | syn::Ty::Never | syn::Ty::TraitObject(_) | syn::Ty::ImplTrait(_) | syn::Ty::Infer | syn::Ty::Mac(_) => {} } }