|  | use proc_macro2; | 
|  | use syn; | 
|  | use syn::spanned::Spanned; | 
|  |  | 
|  | /// Represent the `derivative` attributes on the input type (`struct`/`enum`). | 
|  | #[derive(Debug, Default)] | 
|  | pub struct Input { | 
|  | /// Whether `Clone` is present and its specific attributes. | 
|  | pub clone: Option<InputClone>, | 
|  | /// Whether `Copy` is present and its specific attributes. | 
|  | pub copy: Option<InputCopy>, | 
|  | /// Whether `Debug` is present and its specific attributes. | 
|  | pub debug: Option<InputDebug>, | 
|  | /// Whether `Default` is present and its specific attributes. | 
|  | pub default: Option<InputDefault>, | 
|  | /// Whether `Eq` is present and its specific attributes. | 
|  | pub eq: Option<InputEq>, | 
|  | /// Whether `Hash` is present and its specific attributes. | 
|  | pub hash: Option<InputHash>, | 
|  | /// Whether `PartialEq` is present and its specific attributes. | 
|  | pub partial_eq: Option<InputPartialEq>, | 
|  | /// Whether `PartialOrd` is present and its specific attributes. | 
|  | pub partial_ord: Option<InputPartialOrd>, | 
|  | /// Whether `Ord` is present and its specific attributes. | 
|  | pub ord: Option<InputOrd>, | 
|  | } | 
|  |  | 
|  | #[derive(Debug, Default)] | 
|  | /// Represent the `derivative` attributes on a field. | 
|  | pub struct Field { | 
|  | /// The parameters for `Clone`. | 
|  | clone: FieldClone, | 
|  | /// The parameters for `Copy`. | 
|  | copy_bound: Option<Vec<syn::WherePredicate>>, | 
|  | /// The parameters for `Debug`. | 
|  | debug: FieldDebug, | 
|  | /// The parameters for `Default`. | 
|  | default: FieldDefault, | 
|  | /// The parameters for `Eq`. | 
|  | eq_bound: Option<Vec<syn::WherePredicate>>, | 
|  | /// The parameters for `Hash`. | 
|  | hash: FieldHash, | 
|  | /// The parameters for `PartialEq`. | 
|  | partial_eq: FieldPartialEq, | 
|  | /// The parameters for `PartialOrd`. | 
|  | partial_ord: FieldPartialOrd, | 
|  | /// The parameters for `Ord`. | 
|  | ord: FieldOrd, | 
|  | } | 
|  |  | 
|  | #[derive(Debug, Default)] | 
|  | /// Represent the `derivative(Clone(…))` attributes on an input. | 
|  | pub struct InputClone { | 
|  | /// The `bound` attribute if present and the corresponding bounds. | 
|  | bounds: Option<Vec<syn::WherePredicate>>, | 
|  | /// Whether the implementation should have an explicit `clone_from`. | 
|  | pub clone_from: bool, | 
|  | } | 
|  |  | 
|  | #[derive(Debug, Default)] | 
|  | /// Represent the `derivative(Clone(…))` attributes on an input. | 
|  | pub struct InputCopy { | 
|  | /// The `bound` attribute if present and the corresponding bounds. | 
|  | bounds: Option<Vec<syn::WherePredicate>>, | 
|  | } | 
|  |  | 
|  | #[derive(Debug, Default)] | 
|  | /// Represent the `derivative(Debug(…))` attributes on an input. | 
|  | pub struct InputDebug { | 
|  | /// The `bound` attribute if present and the corresponding bounds. | 
|  | bounds: Option<Vec<syn::WherePredicate>>, | 
|  | /// Whether the type is marked `transparent`. | 
|  | pub transparent: bool, | 
|  | } | 
|  |  | 
|  | #[derive(Debug, Default)] | 
|  | /// Represent the `derivative(Default(…))` attributes on an input. | 
|  | pub struct InputDefault { | 
|  | /// The `bound` attribute if present and the corresponding bounds. | 
|  | bounds: Option<Vec<syn::WherePredicate>>, | 
|  | /// Whether the type is marked with `new`. | 
|  | pub new: bool, | 
|  | } | 
|  |  | 
|  | #[derive(Debug, Default)] | 
|  | /// Represent the `derivative(Eq(…))` attributes on an input. | 
|  | pub struct InputEq { | 
|  | /// The `bound` attribute if present and the corresponding bounds. | 
|  | bounds: Option<Vec<syn::WherePredicate>>, | 
|  | } | 
|  |  | 
|  | #[derive(Debug, Default)] | 
|  | /// Represent the `derivative(Hash(…))` attributes on an input. | 
|  | pub struct InputHash { | 
|  | /// The `bound` attribute if present and the corresponding bounds. | 
|  | bounds: Option<Vec<syn::WherePredicate>>, | 
|  | } | 
|  |  | 
|  | #[derive(Debug, Default)] | 
|  | /// Represent the `derivative(PartialEq(…))` attributes on an input. | 
|  | pub struct InputPartialEq { | 
|  | /// The `bound` attribute if present and the corresponding bounds. | 
|  | bounds: Option<Vec<syn::WherePredicate>>, | 
|  | } | 
|  |  | 
|  | #[derive(Debug, Default)] | 
|  | /// Represent the `derivative(PartialOrd(…))` attributes on an input. | 
|  | pub struct InputPartialOrd { | 
|  | /// The `bound` attribute if present and the corresponding bounds. | 
|  | bounds: Option<Vec<syn::WherePredicate>>, | 
|  | /// Allow `derivative(PartialOrd)` on enums: | 
|  | on_enum: bool, | 
|  | } | 
|  |  | 
|  | #[derive(Debug, Default)] | 
|  | /// Represent the `derivative(Ord(…))` attributes on an input. | 
|  | pub struct InputOrd { | 
|  | /// The `bound` attribute if present and the corresponding bounds. | 
|  | bounds: Option<Vec<syn::WherePredicate>>, | 
|  | /// Allow `derivative(Ord)` on enums: | 
|  | on_enum: bool, | 
|  | } | 
|  |  | 
|  | #[derive(Debug, Default)] | 
|  | /// Represents the `derivative(Clone(…))` attributes on a field. | 
|  | pub struct FieldClone { | 
|  | /// The `bound` attribute if present and the corresponding bounds. | 
|  | bounds: Option<Vec<syn::WherePredicate>>, | 
|  | /// The `clone_with` attribute if present and the path to the cloning function. | 
|  | clone_with: Option<syn::Path>, | 
|  | } | 
|  |  | 
|  | #[derive(Debug, Default)] | 
|  | /// Represents the `derivative(Debug(…))` attributes on a field. | 
|  | pub struct FieldDebug { | 
|  | /// The `bound` attribute if present and the corresponding bounds. | 
|  | bounds: Option<Vec<syn::WherePredicate>>, | 
|  | /// The `format_with` attribute if present and the path to the formatting function. | 
|  | format_with: Option<syn::Path>, | 
|  | /// Whether the field is to be ignored from output. | 
|  | ignore: bool, | 
|  | } | 
|  |  | 
|  | #[derive(Debug, Default)] | 
|  | /// Represent the `derivative(Default(…))` attributes on a field. | 
|  | pub struct FieldDefault { | 
|  | /// The `bound` attribute if present and the corresponding bounds. | 
|  | bounds: Option<Vec<syn::WherePredicate>>, | 
|  | /// The default value for the field if present. | 
|  | pub value: Option<proc_macro2::TokenStream>, | 
|  | } | 
|  |  | 
|  | #[derive(Debug, Default)] | 
|  | /// Represents the `derivative(Hash(…))` attributes on a field. | 
|  | pub struct FieldHash { | 
|  | /// The `bound` attribute if present and the corresponding bounds. | 
|  | bounds: Option<Vec<syn::WherePredicate>>, | 
|  | /// The `hash_with` attribute if present and the path to the hashing function. | 
|  | hash_with: Option<syn::Path>, | 
|  | /// Whether the field is to be ignored when hashing. | 
|  | ignore: bool, | 
|  | } | 
|  |  | 
|  | #[derive(Debug, Default)] | 
|  | /// Represent the `derivative(PartialEq(…))` attributes on a field. | 
|  | pub struct FieldPartialEq { | 
|  | /// The `bound` attribute if present and the corresponding bounds. | 
|  | bounds: Option<Vec<syn::WherePredicate>>, | 
|  | /// The `compare_with` attribute if present and the path to the comparison function. | 
|  | compare_with: Option<syn::Path>, | 
|  | /// Whether the field is to be ignored when comparing. | 
|  | ignore: bool, | 
|  | } | 
|  |  | 
|  | #[derive(Debug, Default)] | 
|  | /// Represent the `derivative(PartialOrd(…))` attributes on a field. | 
|  | pub struct FieldPartialOrd { | 
|  | /// The `bound` attribute if present and the corresponding bounds. | 
|  | bounds: Option<Vec<syn::WherePredicate>>, | 
|  | /// The `compare_with` attribute if present and the path to the comparison function. | 
|  | compare_with: Option<syn::Path>, | 
|  | /// Whether the field is to be ignored when comparing. | 
|  | ignore: bool, | 
|  | } | 
|  |  | 
|  | #[derive(Debug, Default)] | 
|  | /// Represent the `derivative(Ord(…))` attributes on a field. | 
|  | pub struct FieldOrd { | 
|  | /// The `bound` attribute if present and the corresponding bounds. | 
|  | bounds: Option<Vec<syn::WherePredicate>>, | 
|  | /// The `compare_with` attribute if present and the path to the comparison function. | 
|  | compare_with: Option<syn::Path>, | 
|  | /// Whether the field is to be ignored when comparing. | 
|  | ignore: bool, | 
|  | } | 
|  |  | 
|  | macro_rules! for_all_attr { | 
|  | ($errors:ident; for ($name:ident, $value:ident) in $attrs:expr; $($body:tt)*) => { | 
|  | for meta_items in $attrs.iter() { | 
|  | let meta_items = derivative_attribute(meta_items.parse_meta(), $errors); | 
|  | if let Some(meta_items) = meta_items { | 
|  | for meta_item in meta_items.iter() { | 
|  | let meta_item = read_items(meta_item, $errors); | 
|  | let MetaItem($name, $value) = try!(meta_item); | 
|  | match $name.to_string().as_ref() { | 
|  | $($body)* | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | }; | 
|  | } | 
|  |  | 
|  | macro_rules! match_attributes { | 
|  | ($errors:ident for $trait:expr; let Some($name:ident) = $unwrapped:expr; for $value:ident in $values:expr; $($body:tt)* ) => { | 
|  | let mut $name = $unwrapped.take().unwrap_or_default(); | 
|  |  | 
|  | match_attributes! { | 
|  | $errors for $trait; | 
|  | for $value in $values; | 
|  | $($body)* | 
|  | } | 
|  |  | 
|  | $unwrapped = Some($name); | 
|  | }; | 
|  |  | 
|  | ($errors:ident for $trait:expr; for $value:ident in $values:expr; $($body:tt)* ) => { | 
|  | for (name, $value) in $values { | 
|  | match name { | 
|  | Some(ident) => { | 
|  | match ident.to_string().as_ref() { | 
|  | $($body)* | 
|  | unknown => { | 
|  | let message = format!("Unknown attribute `{}` for trait `{}`", unknown, $trait); | 
|  | $errors.extend(quote_spanned! {ident.span()=> | 
|  | compile_error!(#message); | 
|  | }); | 
|  | } | 
|  | } | 
|  | } | 
|  | None => { | 
|  | let value = $value.expect("Expected value to be passed"); | 
|  | match value.value().as_ref() { | 
|  | $($body)* | 
|  | unknown => { | 
|  | let message = format!("Unknown attribute `{}` for trait `{}`", unknown, $trait); | 
|  | let span = value.span(); | 
|  | $errors.extend(quote_spanned! {span=> | 
|  | compile_error!(#message); | 
|  | }); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | }; | 
|  | } | 
|  |  | 
|  | impl Input { | 
|  | /// Parse the `derivative` attributes on a type. | 
|  | #[allow(clippy::cognitive_complexity)] // mostly macros | 
|  | pub fn from_ast( | 
|  | attrs: &[syn::Attribute], | 
|  | errors: &mut proc_macro2::TokenStream, | 
|  | ) -> Result<Input, ()> { | 
|  | let mut input = Input::default(); | 
|  |  | 
|  | for_all_attr! { | 
|  | errors; | 
|  | for (name, values) in attrs; | 
|  | "Clone" => { | 
|  | match_attributes! { | 
|  | errors for "Clone"; | 
|  | let Some(clone) = input.clone; | 
|  | for value in values; | 
|  | "bound" => parse_bound(&mut clone.bounds, value, errors), | 
|  | "clone_from" => { | 
|  | clone.clone_from = parse_boolean_meta_item(value, true, "clone_from", errors); | 
|  | } | 
|  | } | 
|  | } | 
|  | "Copy" => { | 
|  | match_attributes! { | 
|  | errors for "Copy"; | 
|  | let Some(copy) = input.copy; | 
|  | for value in values; | 
|  | "bound" => parse_bound(&mut copy.bounds, value, errors), | 
|  | } | 
|  | } | 
|  | "Debug" => { | 
|  | match_attributes! { | 
|  | errors for "Debug"; | 
|  | let Some(debug) = input.debug; | 
|  | for value in values; | 
|  | "bound" => parse_bound(&mut debug.bounds, value, errors), | 
|  | "transparent" => { | 
|  | debug.transparent = parse_boolean_meta_item(value, true, "transparent", errors); | 
|  | } | 
|  | } | 
|  | } | 
|  | "Default" => { | 
|  | match_attributes! { | 
|  | errors for "Default"; | 
|  | let Some(default) = input.default; | 
|  | for value in values; | 
|  | "bound" => parse_bound(&mut default.bounds, value, errors), | 
|  | "new" => { | 
|  | default.new = parse_boolean_meta_item(value, true, "new", errors); | 
|  | } | 
|  | } | 
|  | } | 
|  | "Eq" => { | 
|  | match_attributes! { | 
|  | errors for "Eq"; | 
|  | let Some(eq) = input.eq; | 
|  | for value in values; | 
|  | "bound" => parse_bound(&mut eq.bounds, value, errors), | 
|  | } | 
|  | } | 
|  | "Hash" => { | 
|  | match_attributes! { | 
|  | errors for "Hash"; | 
|  | let Some(hash) = input.hash; | 
|  | for value in values; | 
|  | "bound" => parse_bound(&mut hash.bounds, value, errors), | 
|  | } | 
|  | } | 
|  | "PartialEq" => { | 
|  | match_attributes! { | 
|  | errors for "PartialEq"; | 
|  | let Some(partial_eq) = input.partial_eq; | 
|  | for value in values; | 
|  | "bound" => parse_bound(&mut partial_eq.bounds, value, errors), | 
|  | "feature_allow_slow_enum" => (), // backward compatibility, now unnecessary | 
|  | } | 
|  | } | 
|  | "PartialOrd" => { | 
|  | match_attributes! { | 
|  | errors for "PartialOrd"; | 
|  | let Some(partial_ord) = input.partial_ord; | 
|  | for value in values; | 
|  | "bound" => parse_bound(&mut partial_ord.bounds, value, errors), | 
|  | "feature_allow_slow_enum" => { | 
|  | partial_ord.on_enum = parse_boolean_meta_item(value, true, "feature_allow_slow_enum", errors); | 
|  | } | 
|  | } | 
|  | } | 
|  | "Ord" => { | 
|  | match_attributes! { | 
|  | errors for "Ord"; | 
|  | let Some(ord) = input.ord; | 
|  | for value in values; | 
|  | "bound" => parse_bound(&mut ord.bounds, value, errors), | 
|  | "feature_allow_slow_enum" => { | 
|  | ord.on_enum = parse_boolean_meta_item(value, true, "feature_allow_slow_enum", errors); | 
|  | } | 
|  | } | 
|  | } | 
|  | unknown => { | 
|  | let message = format!("deriving `{}` is not supported by derivative", unknown); | 
|  | errors.extend(quote_spanned! {name.span()=> | 
|  | compile_error!(#message); | 
|  | }); | 
|  | } | 
|  | } | 
|  |  | 
|  | Ok(input) | 
|  | } | 
|  |  | 
|  | pub fn clone_bound(&self) -> Option<&[syn::WherePredicate]> { | 
|  | self.clone | 
|  | .as_ref() | 
|  | .and_then(|d| d.bounds.as_ref().map(Vec::as_slice)) | 
|  | } | 
|  |  | 
|  | pub fn clone_from(&self) -> bool { | 
|  | self.clone.as_ref().map_or(false, |d| d.clone_from) | 
|  | } | 
|  |  | 
|  | pub fn copy_bound(&self) -> Option<&[syn::WherePredicate]> { | 
|  | self.copy | 
|  | .as_ref() | 
|  | .and_then(|d| d.bounds.as_ref().map(Vec::as_slice)) | 
|  | } | 
|  |  | 
|  | pub fn debug_bound(&self) -> Option<&[syn::WherePredicate]> { | 
|  | self.debug | 
|  | .as_ref() | 
|  | .and_then(|d| d.bounds.as_ref().map(Vec::as_slice)) | 
|  | } | 
|  |  | 
|  | pub fn debug_transparent(&self) -> bool { | 
|  | self.debug.as_ref().map_or(false, |d| d.transparent) | 
|  | } | 
|  |  | 
|  | pub fn default_bound(&self) -> Option<&[syn::WherePredicate]> { | 
|  | self.default | 
|  | .as_ref() | 
|  | .and_then(|d| d.bounds.as_ref().map(Vec::as_slice)) | 
|  | } | 
|  |  | 
|  | pub fn eq_bound(&self) -> Option<&[syn::WherePredicate]> { | 
|  | self.eq | 
|  | .as_ref() | 
|  | .and_then(|d| d.bounds.as_ref().map(Vec::as_slice)) | 
|  | } | 
|  |  | 
|  | pub fn hash_bound(&self) -> Option<&[syn::WherePredicate]> { | 
|  | self.hash | 
|  | .as_ref() | 
|  | .and_then(|d| d.bounds.as_ref().map(Vec::as_slice)) | 
|  | } | 
|  |  | 
|  | pub fn partial_eq_bound(&self) -> Option<&[syn::WherePredicate]> { | 
|  | self.partial_eq | 
|  | .as_ref() | 
|  | .and_then(|d| d.bounds.as_ref().map(Vec::as_slice)) | 
|  | } | 
|  |  | 
|  | pub fn partial_ord_bound(&self) -> Option<&[syn::WherePredicate]> { | 
|  | self.partial_ord | 
|  | .as_ref() | 
|  | .and_then(|d| d.bounds.as_ref().map(Vec::as_slice)) | 
|  | } | 
|  |  | 
|  | pub fn ord_bound(&self) -> Option<&[syn::WherePredicate]> { | 
|  | self.ord | 
|  | .as_ref() | 
|  | .and_then(|d| d.bounds.as_ref().map(Vec::as_slice)) | 
|  | } | 
|  |  | 
|  | pub fn partial_ord_on_enum(&self) -> bool { | 
|  | self.partial_ord.as_ref().map_or(false, |d| d.on_enum) | 
|  | } | 
|  |  | 
|  | pub fn ord_on_enum(&self) -> bool { | 
|  | self.ord.as_ref().map_or(false, |d| d.on_enum) | 
|  | } | 
|  | } | 
|  |  | 
|  | impl Field { | 
|  | /// Parse the `derivative` attributes on a type. | 
|  | #[allow(clippy::cognitive_complexity)] // mostly macros | 
|  | pub fn from_ast( | 
|  | field: &syn::Field, | 
|  | errors: &mut proc_macro2::TokenStream, | 
|  | ) -> Result<Field, ()> { | 
|  | let mut out = Field::default(); | 
|  |  | 
|  | for_all_attr! { | 
|  | errors; | 
|  | for (name, values) in field.attrs; | 
|  | "Clone" => { | 
|  | match_attributes! { | 
|  | errors for "Clone"; | 
|  | for value in values; | 
|  | "bound" => parse_bound(&mut out.clone.bounds, value, errors), | 
|  | "clone_with" => { | 
|  | let path = value.expect("`clone_with` needs a value"); | 
|  | out.clone.clone_with = parse_str_lit(&path, errors).ok(); | 
|  | } | 
|  | } | 
|  | } | 
|  | "Debug" => { | 
|  | match_attributes! { | 
|  | errors for "Debug"; | 
|  | for value in values; | 
|  | "bound" => parse_bound(&mut out.debug.bounds, value, errors), | 
|  | "format_with" => { | 
|  | let path = value.expect("`format_with` needs a value"); | 
|  | out.debug.format_with = parse_str_lit(&path, errors).ok(); | 
|  | } | 
|  | "ignore" => { | 
|  | out.debug.ignore = parse_boolean_meta_item(value, true, "ignore", errors); | 
|  | } | 
|  | } | 
|  | } | 
|  | "Default" => { | 
|  | match_attributes! { | 
|  | errors for "Default"; | 
|  | for value in values; | 
|  | "bound" => parse_bound(&mut out.default.bounds, value, errors), | 
|  | "value" => { | 
|  | let value = value.expect("`value` needs a value"); | 
|  | out.default.value = parse_str_lit(&value, errors).ok(); | 
|  | } | 
|  | } | 
|  | } | 
|  | "Eq" => { | 
|  | match_attributes! { | 
|  | errors for "Eq"; | 
|  | for value in values; | 
|  | "bound" => parse_bound(&mut out.eq_bound, value, errors), | 
|  | } | 
|  | } | 
|  | "Hash" => { | 
|  | match_attributes! { | 
|  | errors for "Hash"; | 
|  | for value in values; | 
|  | "bound" => parse_bound(&mut out.hash.bounds, value, errors), | 
|  | "hash_with" => { | 
|  | let path = value.expect("`hash_with` needs a value"); | 
|  | out.hash.hash_with = parse_str_lit(&path, errors).ok(); | 
|  | } | 
|  | "ignore" => { | 
|  | out.hash.ignore = parse_boolean_meta_item(value, true, "ignore", errors); | 
|  | } | 
|  | } | 
|  | } | 
|  | "PartialEq" => { | 
|  | match_attributes! { | 
|  | errors for "PartialEq"; | 
|  | for value in values; | 
|  | "bound" => parse_bound(&mut out.partial_eq.bounds, value, errors), | 
|  | "compare_with" => { | 
|  | let path = value.expect("`compare_with` needs a value"); | 
|  | out.partial_eq.compare_with = parse_str_lit(&path, errors).ok(); | 
|  | } | 
|  | "ignore" => { | 
|  | out.partial_eq.ignore = parse_boolean_meta_item(value, true, "ignore", errors); | 
|  | } | 
|  | } | 
|  | } | 
|  | "PartialOrd" => { | 
|  | match_attributes! { | 
|  | errors for "PartialOrd"; | 
|  | for value in values; | 
|  | "bound" => parse_bound(&mut out.partial_ord.bounds, value, errors), | 
|  | "compare_with" => { | 
|  | let path = value.expect("`compare_with` needs a value"); | 
|  | out.partial_ord.compare_with = parse_str_lit(&path, errors).ok(); | 
|  | } | 
|  | "ignore" => { | 
|  | out.partial_ord.ignore = parse_boolean_meta_item(value, true, "ignore", errors); | 
|  | } | 
|  | } | 
|  | } | 
|  | "Ord" => { | 
|  | match_attributes! { | 
|  | errors for "Ord"; | 
|  | for value in values; | 
|  | "bound" => parse_bound(&mut out.ord.bounds, value, errors), | 
|  | "compare_with" => { | 
|  | let path = value.expect("`compare_with` needs a value"); | 
|  | out.ord.compare_with = parse_str_lit(&path, errors).ok(); | 
|  | } | 
|  | "ignore" => { | 
|  | out.ord.ignore = parse_boolean_meta_item(value, true, "ignore", errors); | 
|  | } | 
|  | } | 
|  | } | 
|  | unknown => { | 
|  | let message = format!("deriving `{}` is not supported by derivative", unknown); | 
|  | errors.extend(quote_spanned! {name.span()=> | 
|  | compile_error!(#message); | 
|  | }); | 
|  | } | 
|  | } | 
|  |  | 
|  | Ok(out) | 
|  | } | 
|  |  | 
|  | pub fn clone_bound(&self) -> Option<&[syn::WherePredicate]> { | 
|  | self.clone.bounds.as_ref().map(Vec::as_slice) | 
|  | } | 
|  |  | 
|  | pub fn clone_with(&self) -> Option<&syn::Path> { | 
|  | self.clone.clone_with.as_ref() | 
|  | } | 
|  |  | 
|  | pub fn copy_bound(&self) -> Option<&[syn::WherePredicate]> { | 
|  | self.copy_bound.as_ref().map(Vec::as_slice) | 
|  | } | 
|  |  | 
|  | pub fn debug_bound(&self) -> Option<&[syn::WherePredicate]> { | 
|  | self.debug.bounds.as_ref().map(Vec::as_slice) | 
|  | } | 
|  |  | 
|  | pub fn debug_format_with(&self) -> Option<&syn::Path> { | 
|  | self.debug.format_with.as_ref() | 
|  | } | 
|  |  | 
|  | pub fn ignore_debug(&self) -> bool { | 
|  | self.debug.ignore | 
|  | } | 
|  |  | 
|  | pub fn ignore_hash(&self) -> bool { | 
|  | self.hash.ignore | 
|  | } | 
|  |  | 
|  | pub fn default_bound(&self) -> Option<&[syn::WherePredicate]> { | 
|  | self.default.bounds.as_ref().map(Vec::as_slice) | 
|  | } | 
|  |  | 
|  | pub fn default_value(&self) -> Option<&proc_macro2::TokenStream> { | 
|  | self.default.value.as_ref() | 
|  | } | 
|  |  | 
|  | pub fn eq_bound(&self) -> Option<&[syn::WherePredicate]> { | 
|  | self.eq_bound.as_ref().map(Vec::as_slice) | 
|  | } | 
|  |  | 
|  | pub fn hash_bound(&self) -> Option<&[syn::WherePredicate]> { | 
|  | self.hash.bounds.as_ref().map(Vec::as_slice) | 
|  | } | 
|  |  | 
|  | pub fn hash_with(&self) -> Option<&syn::Path> { | 
|  | self.hash.hash_with.as_ref() | 
|  | } | 
|  |  | 
|  | pub fn partial_eq_bound(&self) -> Option<&[syn::WherePredicate]> { | 
|  | self.partial_eq.bounds.as_ref().map(Vec::as_slice) | 
|  | } | 
|  |  | 
|  | pub fn partial_ord_bound(&self) -> Option<&[syn::WherePredicate]> { | 
|  | self.partial_ord.bounds.as_ref().map(Vec::as_slice) | 
|  | } | 
|  |  | 
|  | pub fn ord_bound(&self) -> Option<&[syn::WherePredicate]> { | 
|  | self.ord.bounds.as_ref().map(Vec::as_slice) | 
|  | } | 
|  |  | 
|  | pub fn partial_eq_compare_with(&self) -> Option<&syn::Path> { | 
|  | self.partial_eq.compare_with.as_ref() | 
|  | } | 
|  |  | 
|  | pub fn partial_ord_compare_with(&self) -> Option<&syn::Path> { | 
|  | self.partial_ord.compare_with.as_ref() | 
|  | } | 
|  |  | 
|  | pub fn ord_compare_with(&self) -> Option<&syn::Path> { | 
|  | self.ord.compare_with.as_ref() | 
|  | } | 
|  |  | 
|  | pub fn ignore_partial_eq(&self) -> bool { | 
|  | self.partial_eq.ignore | 
|  | } | 
|  |  | 
|  | pub fn ignore_partial_ord(&self) -> bool { | 
|  | self.partial_ord.ignore | 
|  | } | 
|  |  | 
|  | pub fn ignore_ord(&self) -> bool { | 
|  | self.ord.ignore | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Represent an attribute. | 
|  | /// | 
|  | /// We only have a limited set of possible attributes: | 
|  | /// | 
|  | /// * `#[derivative(Debug)]` is represented as `(Debug, [])`; | 
|  | /// * `#[derivative(Debug="foo")]` is represented as `(Debug, [(None, Some("foo"))])`; | 
|  | /// * `#[derivative(Debug(foo="bar")]` is represented as `(Debug, [(Some(foo), Some("bar"))])`. | 
|  | struct MetaItem<'a>( | 
|  | &'a syn::Ident, | 
|  | Vec<(Option<&'a syn::Ident>, Option<&'a syn::LitStr>)>, | 
|  | ); | 
|  |  | 
|  | /// Parse an arbitrary item for our limited `MetaItem` subset. | 
|  | fn read_items<'a>(item: &'a syn::NestedMeta, errors: &mut proc_macro2::TokenStream) -> Result<MetaItem<'a>, ()> { | 
|  | let item = match *item { | 
|  | syn::NestedMeta::Meta(ref item) => item, | 
|  | syn::NestedMeta::Lit(ref lit) => { | 
|  | errors.extend(quote_spanned! {lit.span()=> | 
|  | compile_error!("expected meta-item but found literal"); | 
|  | }); | 
|  |  | 
|  | return Err(()); | 
|  | } | 
|  | }; | 
|  | match *item { | 
|  | syn::Meta::Path(ref path) => match path.get_ident() { | 
|  | Some(name) => Ok(MetaItem(name, Vec::new())), | 
|  | None => { | 
|  | errors.extend(quote_spanned! {path.span()=> | 
|  | compile_error!("expected derivative attribute to be a string, but found a path"); | 
|  | }); | 
|  |  | 
|  | Err(()) | 
|  | } | 
|  | }, | 
|  | syn::Meta::List(syn::MetaList { | 
|  | ref path, | 
|  | nested: ref values, | 
|  | .. | 
|  | }) => { | 
|  | let values = values | 
|  | .iter() | 
|  | .map(|value| { | 
|  | if let syn::NestedMeta::Meta(syn::Meta::NameValue(syn::MetaNameValue { | 
|  | ref path, | 
|  | lit: ref value, | 
|  | .. | 
|  | })) = *value | 
|  | { | 
|  | let (name, value) = ensure_str_lit(&path, &value, errors)?; | 
|  |  | 
|  | Ok((Some(name), Some(value))) | 
|  | } else { | 
|  | errors.extend(quote_spanned! {value.span()=> | 
|  | compile_error!("expected named value"); | 
|  | }); | 
|  |  | 
|  | Err(()) | 
|  | } | 
|  | }) | 
|  | .collect::<Result<_, _>>()?; | 
|  |  | 
|  | let name = match path.get_ident() { | 
|  | Some(name) => name, | 
|  | None => { | 
|  | errors.extend(quote_spanned! {path.span()=> | 
|  | compile_error!("expected derivative attribute to be a string, but found a path"); | 
|  | }); | 
|  |  | 
|  | return Err(()); | 
|  | } | 
|  | }; | 
|  |  | 
|  | Ok(MetaItem(name, values)) | 
|  | } | 
|  | syn::Meta::NameValue(syn::MetaNameValue { | 
|  | ref path, | 
|  | lit: ref value, | 
|  | .. | 
|  | }) => { | 
|  | let (name, value) = ensure_str_lit(&path, &value, errors)?; | 
|  |  | 
|  | Ok(MetaItem(name, vec![(None, Some(value))])) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Filter the `derivative` items from an attribute. | 
|  | fn derivative_attribute( | 
|  | meta: syn::parse::Result<syn::Meta>, | 
|  | errors: &mut proc_macro2::TokenStream, | 
|  | ) -> Option<syn::punctuated::Punctuated<syn::NestedMeta, syn::token::Comma>> { | 
|  | match meta { | 
|  | Ok(syn::Meta::List(syn::MetaList { | 
|  | path, nested: mis, .. | 
|  | })) => { | 
|  | if path | 
|  | .get_ident() | 
|  | .map_or(false, |ident| ident == "derivative") | 
|  | { | 
|  | Some(mis) | 
|  | } else { | 
|  | None | 
|  | } | 
|  | } | 
|  | Ok(_) => None, | 
|  | Err(e) => { | 
|  | let message = format!("invalid attribute: {}", e); | 
|  | errors.extend(quote_spanned! {e.span()=> | 
|  | compile_error!(#message); | 
|  | }); | 
|  |  | 
|  | None | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Parse an item value as a boolean. Accepted values are the string literal `"true"` and | 
|  | /// `"false"`. The `default` parameter specifies what the value of the boolean is when only its | 
|  | /// name is specified (eg. `Debug="ignore"` is equivalent to `Debug(ignore="true")`). The `name` | 
|  | /// parameter is used for error reporting. | 
|  | fn parse_boolean_meta_item( | 
|  | item: Option<&syn::LitStr>, | 
|  | default: bool, | 
|  | name: &str, | 
|  | errors: &mut proc_macro2::TokenStream, | 
|  | ) -> bool { | 
|  | if let Some(item) = item.as_ref() { | 
|  | match item.value().as_ref() { | 
|  | "true" => true, | 
|  | "false" => false, | 
|  | val => { | 
|  | if val == name { | 
|  | true | 
|  | } else { | 
|  | let message = format!( | 
|  | r#"expected `"true"` or `"false"` for `{}`, got `{}`"#, | 
|  | name, val | 
|  | ); | 
|  | errors.extend(quote_spanned! {item.span()=> | 
|  | compile_error!(#message); | 
|  | }); | 
|  |  | 
|  | default | 
|  | } | 
|  | } | 
|  | } | 
|  | } else { | 
|  | default | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Parse a `bound` item. | 
|  | fn parse_bound( | 
|  | opt_bounds: &mut Option<Vec<syn::WherePredicate>>, | 
|  | value: Option<&syn::LitStr>, | 
|  | errors: &mut proc_macro2::TokenStream, | 
|  | ) { | 
|  | let bound = value.expect("`bound` needs a value"); | 
|  | let bound_value = bound.value(); | 
|  |  | 
|  | *opt_bounds = if !bound_value.is_empty() { | 
|  | let where_string = syn::LitStr::new(&format!("where {}", bound_value), bound.span()); | 
|  |  | 
|  | let bounds = parse_str_lit::<syn::WhereClause>(&where_string, errors) | 
|  | .map(|wh| wh.predicates.into_iter().collect()); | 
|  |  | 
|  | match bounds { | 
|  | Ok(bounds) => Some(bounds), | 
|  | Err(_) => { | 
|  | errors.extend(quote_spanned! {where_string.span()=> | 
|  | compile_error!("could not parse bound"); | 
|  | }); | 
|  |  | 
|  | None | 
|  | } | 
|  | } | 
|  | } else { | 
|  | Some(vec![]) | 
|  | }; | 
|  | } | 
|  |  | 
|  | fn parse_str_lit<T>(value: &syn::LitStr, errors: &mut proc_macro2::TokenStream) -> Result<T, ()> | 
|  | where | 
|  | T: syn::parse::Parse, | 
|  | { | 
|  | match value.parse() { | 
|  | Ok(value) => Ok(value), | 
|  | Err(e) => { | 
|  | let message = format!("could not parse string literal: {}", e); | 
|  | errors.extend(quote_spanned! {value.span()=> | 
|  | compile_error!(#message); | 
|  | }); | 
|  | Err(()) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | fn ensure_str_lit<'a>( | 
|  | attr_path: &'a syn::Path, | 
|  | lit: &'a syn::Lit, | 
|  | errors: &mut proc_macro2::TokenStream, | 
|  | ) -> Result<(&'a syn::Ident, &'a syn::LitStr), ()> { | 
|  | let attr_name = match attr_path.get_ident() { | 
|  | Some(attr_name) => attr_name, | 
|  | None => { | 
|  | errors.extend(quote_spanned! {attr_path.span()=> | 
|  | compile_error!("expected derivative attribute to be a string, but found a path"); | 
|  | }); | 
|  | return Err(()); | 
|  | } | 
|  | }; | 
|  |  | 
|  | if let syn::Lit::Str(ref lit) = *lit { | 
|  | Ok((attr_name, lit)) | 
|  | } else { | 
|  | let message = format!( | 
|  | "expected derivative {} attribute to be a string: `{} = \"...\"`", | 
|  | attr_name, attr_name | 
|  | ); | 
|  | errors.extend(quote_spanned! {lit.span()=> | 
|  | compile_error!(#message); | 
|  | }); | 
|  | Err(()) | 
|  | } | 
|  | } |