1 use proc_macro2;
2 use syn;
3 use syn::spanned::Spanned;
4 
5 /// Represent the `derivative` attributes on the input type (`struct`/`enum`).
6 #[derive(Debug, Default)]
7 pub struct Input {
8     /// Whether `Clone` is present and its specific attributes.
9     pub clone: Option<InputClone>,
10     /// Whether `Copy` is present and its specific attributes.
11     pub copy: Option<InputCopy>,
12     /// Whether `Debug` is present and its specific attributes.
13     pub debug: Option<InputDebug>,
14     /// Whether `Default` is present and its specific attributes.
15     pub default: Option<InputDefault>,
16     /// Whether `Eq` is present and its specific attributes.
17     pub eq: Option<InputEq>,
18     /// Whether `Hash` is present and its specific attributes.
19     pub hash: Option<InputHash>,
20     /// Whether `PartialEq` is present and its specific attributes.
21     pub partial_eq: Option<InputPartialEq>,
22     /// Whether `PartialOrd` is present and its specific attributes.
23     pub partial_ord: Option<InputPartialOrd>,
24     /// Whether `Ord` is present and its specific attributes.
25     pub ord: Option<InputOrd>,
26 }
27 
28 #[derive(Debug, Default)]
29 /// Represent the `derivative` attributes on a field.
30 pub struct Field {
31     /// The parameters for `Clone`.
32     clone: FieldClone,
33     /// The parameters for `Copy`.
34     copy_bound: Option<Vec<syn::WherePredicate>>,
35     /// The parameters for `Debug`.
36     debug: FieldDebug,
37     /// The parameters for `Default`.
38     default: FieldDefault,
39     /// The parameters for `Eq`.
40     eq_bound: Option<Vec<syn::WherePredicate>>,
41     /// The parameters for `Hash`.
42     hash: FieldHash,
43     /// The parameters for `PartialEq`.
44     partial_eq: FieldPartialEq,
45     /// The parameters for `PartialOrd`.
46     partial_ord: FieldPartialOrd,
47     /// The parameters for `Ord`.
48     ord: FieldOrd,
49 }
50 
51 #[derive(Debug, Default)]
52 /// Represent the `derivative(Clone(…))` attributes on an input.
53 pub struct InputClone {
54     /// The `bound` attribute if present and the corresponding bounds.
55     bounds: Option<Vec<syn::WherePredicate>>,
56     /// Whether the implementation should have an explicit `clone_from`.
57     pub clone_from: bool,
58 }
59 
60 #[derive(Debug, Default)]
61 /// Represent the `derivative(Clone(…))` attributes on an input.
62 pub struct InputCopy {
63     /// The `bound` attribute if present and the corresponding bounds.
64     bounds: Option<Vec<syn::WherePredicate>>,
65 }
66 
67 #[derive(Debug, Default)]
68 /// Represent the `derivative(Debug(…))` attributes on an input.
69 pub struct InputDebug {
70     /// The `bound` attribute if present and the corresponding bounds.
71     bounds: Option<Vec<syn::WherePredicate>>,
72     /// Whether the type is marked `transparent`.
73     pub transparent: bool,
74 }
75 
76 #[derive(Debug, Default)]
77 /// Represent the `derivative(Default(…))` attributes on an input.
78 pub struct InputDefault {
79     /// The `bound` attribute if present and the corresponding bounds.
80     bounds: Option<Vec<syn::WherePredicate>>,
81     /// Whether the type is marked with `new`.
82     pub new: bool,
83 }
84 
85 #[derive(Debug, Default)]
86 /// Represent the `derivative(Eq(…))` attributes on an input.
87 pub struct InputEq {
88     /// The `bound` attribute if present and the corresponding bounds.
89     bounds: Option<Vec<syn::WherePredicate>>,
90 }
91 
92 #[derive(Debug, Default)]
93 /// Represent the `derivative(Hash(…))` attributes on an input.
94 pub struct InputHash {
95     /// The `bound` attribute if present and the corresponding bounds.
96     bounds: Option<Vec<syn::WherePredicate>>,
97 }
98 
99 #[derive(Debug, Default)]
100 /// Represent the `derivative(PartialEq(…))` attributes on an input.
101 pub struct InputPartialEq {
102     /// The `bound` attribute if present and the corresponding bounds.
103     bounds: Option<Vec<syn::WherePredicate>>,
104 }
105 
106 #[derive(Debug, Default)]
107 /// Represent the `derivative(PartialOrd(…))` attributes on an input.
108 pub struct InputPartialOrd {
109     /// The `bound` attribute if present and the corresponding bounds.
110     bounds: Option<Vec<syn::WherePredicate>>,
111     /// Allow `derivative(PartialOrd)` on enums:
112     on_enum: bool,
113 }
114 
115 #[derive(Debug, Default)]
116 /// Represent the `derivative(Ord(…))` attributes on an input.
117 pub struct InputOrd {
118     /// The `bound` attribute if present and the corresponding bounds.
119     bounds: Option<Vec<syn::WherePredicate>>,
120     /// Allow `derivative(Ord)` on enums:
121     on_enum: bool,
122 }
123 
124 #[derive(Debug, Default)]
125 /// Represents the `derivative(Clone(…))` attributes on a field.
126 pub struct FieldClone {
127     /// The `bound` attribute if present and the corresponding bounds.
128     bounds: Option<Vec<syn::WherePredicate>>,
129     /// The `clone_with` attribute if present and the path to the cloning function.
130     clone_with: Option<syn::Path>,
131 }
132 
133 #[derive(Debug, Default)]
134 /// Represents the `derivative(Debug(…))` attributes on a field.
135 pub struct FieldDebug {
136     /// The `bound` attribute if present and the corresponding bounds.
137     bounds: Option<Vec<syn::WherePredicate>>,
138     /// The `format_with` attribute if present and the path to the formatting function.
139     format_with: Option<syn::Path>,
140     /// Whether the field is to be ignored from output.
141     ignore: bool,
142 }
143 
144 #[derive(Debug, Default)]
145 /// Represent the `derivative(Default(…))` attributes on a field.
146 pub struct FieldDefault {
147     /// The `bound` attribute if present and the corresponding bounds.
148     bounds: Option<Vec<syn::WherePredicate>>,
149     /// The default value for the field if present.
150     pub value: Option<proc_macro2::TokenStream>,
151 }
152 
153 #[derive(Debug, Default)]
154 /// Represents the `derivative(Hash(…))` attributes on a field.
155 pub struct FieldHash {
156     /// The `bound` attribute if present and the corresponding bounds.
157     bounds: Option<Vec<syn::WherePredicate>>,
158     /// The `hash_with` attribute if present and the path to the hashing function.
159     hash_with: Option<syn::Path>,
160     /// Whether the field is to be ignored when hashing.
161     ignore: bool,
162 }
163 
164 #[derive(Debug, Default)]
165 /// Represent the `derivative(PartialEq(…))` attributes on a field.
166 pub struct FieldPartialEq {
167     /// The `bound` attribute if present and the corresponding bounds.
168     bounds: Option<Vec<syn::WherePredicate>>,
169     /// The `compare_with` attribute if present and the path to the comparison function.
170     compare_with: Option<syn::Path>,
171     /// Whether the field is to be ignored when comparing.
172     ignore: bool,
173 }
174 
175 #[derive(Debug, Default)]
176 /// Represent the `derivative(PartialOrd(…))` attributes on a field.
177 pub struct FieldPartialOrd {
178     /// The `bound` attribute if present and the corresponding bounds.
179     bounds: Option<Vec<syn::WherePredicate>>,
180     /// The `compare_with` attribute if present and the path to the comparison function.
181     compare_with: Option<syn::Path>,
182     /// Whether the field is to be ignored when comparing.
183     ignore: bool,
184 }
185 
186 #[derive(Debug, Default)]
187 /// Represent the `derivative(Ord(…))` attributes on a field.
188 pub struct FieldOrd {
189     /// The `bound` attribute if present and the corresponding bounds.
190     bounds: Option<Vec<syn::WherePredicate>>,
191     /// The `compare_with` attribute if present and the path to the comparison function.
192     compare_with: Option<syn::Path>,
193     /// Whether the field is to be ignored when comparing.
194     ignore: bool,
195 }
196 
197 macro_rules! for_all_attr {
198     ($errors:ident; for ($name:ident, $value:ident) in $attrs:expr; $($body:tt)*) => {
199         for meta_items in $attrs.iter() {
200             let meta_items = derivative_attribute(meta_items.parse_meta(), $errors);
201             if let Some(meta_items) = meta_items {
202                 for meta_item in meta_items.iter() {
203                     let meta_item = read_items(meta_item, $errors);
204                     let MetaItem($name, $value) = try!(meta_item);
205                     match $name.to_string().as_ref() {
206                         $($body)*
207                     }
208                 }
209             }
210         }
211     };
212 }
213 
214 macro_rules! match_attributes {
215     ($errors:ident for $trait:expr; let Some($name:ident) = $unwrapped:expr; for $value:ident in $values:expr; $($body:tt)* ) => {
216         let mut $name = $unwrapped.take().unwrap_or_default();
217 
218         match_attributes! {
219             $errors for $trait;
220             for $value in $values;
221             $($body)*
222         }
223 
224         $unwrapped = Some($name);
225     };
226 
227     ($errors:ident for $trait:expr; for $value:ident in $values:expr; $($body:tt)* ) => {
228         for (name, $value) in $values {
229             match name {
230                 Some(ident) => {
231                     match ident.to_string().as_ref() {
232                         $($body)*
233                         unknown => {
234                             let message = format!("Unknown attribute `{}` for trait `{}`", unknown, $trait);
235                             $errors.extend(quote_spanned! {ident.span()=>
236                                 compile_error!(#message);
237                             });
238                         }
239                     }
240                 }
241                 None => {
242                     let value = $value.expect("Expected value to be passed");
243                     match value.value().as_ref() {
244                         $($body)*
245                         unknown => {
246                             let message = format!("Unknown attribute `{}` for trait `{}`", unknown, $trait);
247                             let span = value.span();
248                             $errors.extend(quote_spanned! {span=>
249                                 compile_error!(#message);
250                             });
251                         }
252                     }
253                 }
254             }
255         }
256     };
257 }
258 
259 impl Input {
260     /// Parse the `derivative` attributes on a type.
261     #[allow(clippy::cognitive_complexity)] // mostly macros
from_ast( attrs: &[syn::Attribute], errors: &mut proc_macro2::TokenStream, ) -> Result<Input, ()>262     pub fn from_ast(
263         attrs: &[syn::Attribute],
264         errors: &mut proc_macro2::TokenStream,
265     ) -> Result<Input, ()> {
266         let mut input = Input::default();
267 
268         for_all_attr! {
269             errors;
270             for (name, values) in attrs;
271             "Clone" => {
272                 match_attributes! {
273                     errors for "Clone";
274                     let Some(clone) = input.clone;
275                     for value in values;
276                     "bound" => parse_bound(&mut clone.bounds, value, errors),
277                     "clone_from" => {
278                         clone.clone_from = parse_boolean_meta_item(value, true, "clone_from", errors);
279                     }
280                 }
281             }
282             "Copy" => {
283                 match_attributes! {
284                     errors for "Copy";
285                     let Some(copy) = input.copy;
286                     for value in values;
287                     "bound" => parse_bound(&mut copy.bounds, value, errors),
288                 }
289             }
290             "Debug" => {
291                 match_attributes! {
292                     errors for "Debug";
293                     let Some(debug) = input.debug;
294                     for value in values;
295                     "bound" => parse_bound(&mut debug.bounds, value, errors),
296                     "transparent" => {
297                         debug.transparent = parse_boolean_meta_item(value, true, "transparent", errors);
298                     }
299                 }
300             }
301             "Default" => {
302                 match_attributes! {
303                     errors for "Default";
304                     let Some(default) = input.default;
305                     for value in values;
306                     "bound" => parse_bound(&mut default.bounds, value, errors),
307                     "new" => {
308                         default.new = parse_boolean_meta_item(value, true, "new", errors);
309                     }
310                 }
311             }
312             "Eq" => {
313                 match_attributes! {
314                     errors for "Eq";
315                     let Some(eq) = input.eq;
316                     for value in values;
317                     "bound" => parse_bound(&mut eq.bounds, value, errors),
318                 }
319             }
320             "Hash" => {
321                 match_attributes! {
322                     errors for "Hash";
323                     let Some(hash) = input.hash;
324                     for value in values;
325                     "bound" => parse_bound(&mut hash.bounds, value, errors),
326                 }
327             }
328             "PartialEq" => {
329                 match_attributes! {
330                     errors for "PartialEq";
331                     let Some(partial_eq) = input.partial_eq;
332                     for value in values;
333                     "bound" => parse_bound(&mut partial_eq.bounds, value, errors),
334                     "feature_allow_slow_enum" => (), // backward compatibility, now unnecessary
335                 }
336             }
337             "PartialOrd" => {
338                 match_attributes! {
339                     errors for "PartialOrd";
340                     let Some(partial_ord) = input.partial_ord;
341                     for value in values;
342                     "bound" => parse_bound(&mut partial_ord.bounds, value, errors),
343                     "feature_allow_slow_enum" => {
344                         partial_ord.on_enum = parse_boolean_meta_item(value, true, "feature_allow_slow_enum", errors);
345                     }
346                 }
347             }
348             "Ord" => {
349                 match_attributes! {
350                     errors for "Ord";
351                     let Some(ord) = input.ord;
352                     for value in values;
353                     "bound" => parse_bound(&mut ord.bounds, value, errors),
354                     "feature_allow_slow_enum" => {
355                         ord.on_enum = parse_boolean_meta_item(value, true, "feature_allow_slow_enum", errors);
356                     }
357                 }
358             }
359             unknown => {
360                 let message = format!("deriving `{}` is not supported by derivative", unknown);
361                 errors.extend(quote_spanned! {name.span()=>
362                     compile_error!(#message);
363                 });
364             }
365         }
366 
367         Ok(input)
368     }
369 
clone_bound(&self) -> Option<&[syn::WherePredicate]>370     pub fn clone_bound(&self) -> Option<&[syn::WherePredicate]> {
371         self.clone
372             .as_ref()
373             .and_then(|d| d.bounds.as_ref().map(Vec::as_slice))
374     }
375 
clone_from(&self) -> bool376     pub fn clone_from(&self) -> bool {
377         self.clone.as_ref().map_or(false, |d| d.clone_from)
378     }
379 
copy_bound(&self) -> Option<&[syn::WherePredicate]>380     pub fn copy_bound(&self) -> Option<&[syn::WherePredicate]> {
381         self.copy
382             .as_ref()
383             .and_then(|d| d.bounds.as_ref().map(Vec::as_slice))
384     }
385 
debug_bound(&self) -> Option<&[syn::WherePredicate]>386     pub fn debug_bound(&self) -> Option<&[syn::WherePredicate]> {
387         self.debug
388             .as_ref()
389             .and_then(|d| d.bounds.as_ref().map(Vec::as_slice))
390     }
391 
debug_transparent(&self) -> bool392     pub fn debug_transparent(&self) -> bool {
393         self.debug.as_ref().map_or(false, |d| d.transparent)
394     }
395 
default_bound(&self) -> Option<&[syn::WherePredicate]>396     pub fn default_bound(&self) -> Option<&[syn::WherePredicate]> {
397         self.default
398             .as_ref()
399             .and_then(|d| d.bounds.as_ref().map(Vec::as_slice))
400     }
401 
eq_bound(&self) -> Option<&[syn::WherePredicate]>402     pub fn eq_bound(&self) -> Option<&[syn::WherePredicate]> {
403         self.eq
404             .as_ref()
405             .and_then(|d| d.bounds.as_ref().map(Vec::as_slice))
406     }
407 
hash_bound(&self) -> Option<&[syn::WherePredicate]>408     pub fn hash_bound(&self) -> Option<&[syn::WherePredicate]> {
409         self.hash
410             .as_ref()
411             .and_then(|d| d.bounds.as_ref().map(Vec::as_slice))
412     }
413 
partial_eq_bound(&self) -> Option<&[syn::WherePredicate]>414     pub fn partial_eq_bound(&self) -> Option<&[syn::WherePredicate]> {
415         self.partial_eq
416             .as_ref()
417             .and_then(|d| d.bounds.as_ref().map(Vec::as_slice))
418     }
419 
partial_ord_bound(&self) -> Option<&[syn::WherePredicate]>420     pub fn partial_ord_bound(&self) -> Option<&[syn::WherePredicate]> {
421         self.partial_ord
422             .as_ref()
423             .and_then(|d| d.bounds.as_ref().map(Vec::as_slice))
424     }
425 
ord_bound(&self) -> Option<&[syn::WherePredicate]>426     pub fn ord_bound(&self) -> Option<&[syn::WherePredicate]> {
427         self.ord
428             .as_ref()
429             .and_then(|d| d.bounds.as_ref().map(Vec::as_slice))
430     }
431 
partial_ord_on_enum(&self) -> bool432     pub fn partial_ord_on_enum(&self) -> bool {
433         self.partial_ord.as_ref().map_or(false, |d| d.on_enum)
434     }
435 
ord_on_enum(&self) -> bool436     pub fn ord_on_enum(&self) -> bool {
437         self.ord.as_ref().map_or(false, |d| d.on_enum)
438     }
439 }
440 
441 impl Field {
442     /// Parse the `derivative` attributes on a type.
443     #[allow(clippy::cognitive_complexity)] // mostly macros
from_ast( field: &syn::Field, errors: &mut proc_macro2::TokenStream, ) -> Result<Field, ()>444     pub fn from_ast(
445         field: &syn::Field,
446         errors: &mut proc_macro2::TokenStream,
447     ) -> Result<Field, ()> {
448         let mut out = Field::default();
449 
450         for_all_attr! {
451             errors;
452             for (name, values) in field.attrs;
453             "Clone" => {
454                 match_attributes! {
455                     errors for "Clone";
456                     for value in values;
457                     "bound" => parse_bound(&mut out.clone.bounds, value, errors),
458                     "clone_with" => {
459                         let path = value.expect("`clone_with` needs a value");
460                         out.clone.clone_with = parse_str_lit(&path, errors).ok();
461                     }
462                 }
463             }
464             "Debug" => {
465                 match_attributes! {
466                     errors for "Debug";
467                     for value in values;
468                     "bound" => parse_bound(&mut out.debug.bounds, value, errors),
469                     "format_with" => {
470                         let path = value.expect("`format_with` needs a value");
471                         out.debug.format_with = parse_str_lit(&path, errors).ok();
472                     }
473                     "ignore" => {
474                         out.debug.ignore = parse_boolean_meta_item(value, true, "ignore", errors);
475                     }
476                 }
477             }
478             "Default" => {
479                 match_attributes! {
480                     errors for "Default";
481                     for value in values;
482                     "bound" => parse_bound(&mut out.default.bounds, value, errors),
483                     "value" => {
484                         let value = value.expect("`value` needs a value");
485                         out.default.value = parse_str_lit(&value, errors).ok();
486                     }
487                 }
488             }
489             "Eq" => {
490                 match_attributes! {
491                     errors for "Eq";
492                     for value in values;
493                     "bound" => parse_bound(&mut out.eq_bound, value, errors),
494                 }
495             }
496             "Hash" => {
497                 match_attributes! {
498                     errors for "Hash";
499                     for value in values;
500                     "bound" => parse_bound(&mut out.hash.bounds, value, errors),
501                     "hash_with" => {
502                         let path = value.expect("`hash_with` needs a value");
503                         out.hash.hash_with = parse_str_lit(&path, errors).ok();
504                     }
505                     "ignore" => {
506                         out.hash.ignore = parse_boolean_meta_item(value, true, "ignore", errors);
507                     }
508                 }
509             }
510             "PartialEq" => {
511                 match_attributes! {
512                     errors for "PartialEq";
513                     for value in values;
514                     "bound" => parse_bound(&mut out.partial_eq.bounds, value, errors),
515                     "compare_with" => {
516                         let path = value.expect("`compare_with` needs a value");
517                         out.partial_eq.compare_with = parse_str_lit(&path, errors).ok();
518                     }
519                     "ignore" => {
520                         out.partial_eq.ignore = parse_boolean_meta_item(value, true, "ignore", errors);
521                     }
522                 }
523             }
524             "PartialOrd" => {
525                 match_attributes! {
526                     errors for "PartialOrd";
527                     for value in values;
528                     "bound" => parse_bound(&mut out.partial_ord.bounds, value, errors),
529                     "compare_with" => {
530                         let path = value.expect("`compare_with` needs a value");
531                         out.partial_ord.compare_with = parse_str_lit(&path, errors).ok();
532                     }
533                     "ignore" => {
534                         out.partial_ord.ignore = parse_boolean_meta_item(value, true, "ignore", errors);
535                     }
536                 }
537             }
538             "Ord" => {
539                 match_attributes! {
540                     errors for "Ord";
541                     for value in values;
542                     "bound" => parse_bound(&mut out.ord.bounds, value, errors),
543                     "compare_with" => {
544                         let path = value.expect("`compare_with` needs a value");
545                         out.ord.compare_with = parse_str_lit(&path, errors).ok();
546                     }
547                     "ignore" => {
548                         out.ord.ignore = parse_boolean_meta_item(value, true, "ignore", errors);
549                     }
550                 }
551             }
552             unknown => {
553                 let message = format!("deriving `{}` is not supported by derivative", unknown);
554                 errors.extend(quote_spanned! {name.span()=>
555                     compile_error!(#message);
556                 });
557             }
558         }
559 
560         Ok(out)
561     }
562 
clone_bound(&self) -> Option<&[syn::WherePredicate]>563     pub fn clone_bound(&self) -> Option<&[syn::WherePredicate]> {
564         self.clone.bounds.as_ref().map(Vec::as_slice)
565     }
566 
clone_with(&self) -> Option<&syn::Path>567     pub fn clone_with(&self) -> Option<&syn::Path> {
568         self.clone.clone_with.as_ref()
569     }
570 
copy_bound(&self) -> Option<&[syn::WherePredicate]>571     pub fn copy_bound(&self) -> Option<&[syn::WherePredicate]> {
572         self.copy_bound.as_ref().map(Vec::as_slice)
573     }
574 
debug_bound(&self) -> Option<&[syn::WherePredicate]>575     pub fn debug_bound(&self) -> Option<&[syn::WherePredicate]> {
576         self.debug.bounds.as_ref().map(Vec::as_slice)
577     }
578 
debug_format_with(&self) -> Option<&syn::Path>579     pub fn debug_format_with(&self) -> Option<&syn::Path> {
580         self.debug.format_with.as_ref()
581     }
582 
ignore_debug(&self) -> bool583     pub fn ignore_debug(&self) -> bool {
584         self.debug.ignore
585     }
586 
ignore_hash(&self) -> bool587     pub fn ignore_hash(&self) -> bool {
588         self.hash.ignore
589     }
590 
default_bound(&self) -> Option<&[syn::WherePredicate]>591     pub fn default_bound(&self) -> Option<&[syn::WherePredicate]> {
592         self.default.bounds.as_ref().map(Vec::as_slice)
593     }
594 
default_value(&self) -> Option<&proc_macro2::TokenStream>595     pub fn default_value(&self) -> Option<&proc_macro2::TokenStream> {
596         self.default.value.as_ref()
597     }
598 
eq_bound(&self) -> Option<&[syn::WherePredicate]>599     pub fn eq_bound(&self) -> Option<&[syn::WherePredicate]> {
600         self.eq_bound.as_ref().map(Vec::as_slice)
601     }
602 
hash_bound(&self) -> Option<&[syn::WherePredicate]>603     pub fn hash_bound(&self) -> Option<&[syn::WherePredicate]> {
604         self.hash.bounds.as_ref().map(Vec::as_slice)
605     }
606 
hash_with(&self) -> Option<&syn::Path>607     pub fn hash_with(&self) -> Option<&syn::Path> {
608         self.hash.hash_with.as_ref()
609     }
610 
partial_eq_bound(&self) -> Option<&[syn::WherePredicate]>611     pub fn partial_eq_bound(&self) -> Option<&[syn::WherePredicate]> {
612         self.partial_eq.bounds.as_ref().map(Vec::as_slice)
613     }
614 
partial_ord_bound(&self) -> Option<&[syn::WherePredicate]>615     pub fn partial_ord_bound(&self) -> Option<&[syn::WherePredicate]> {
616         self.partial_ord.bounds.as_ref().map(Vec::as_slice)
617     }
618 
ord_bound(&self) -> Option<&[syn::WherePredicate]>619     pub fn ord_bound(&self) -> Option<&[syn::WherePredicate]> {
620         self.ord.bounds.as_ref().map(Vec::as_slice)
621     }
622 
partial_eq_compare_with(&self) -> Option<&syn::Path>623     pub fn partial_eq_compare_with(&self) -> Option<&syn::Path> {
624         self.partial_eq.compare_with.as_ref()
625     }
626 
partial_ord_compare_with(&self) -> Option<&syn::Path>627     pub fn partial_ord_compare_with(&self) -> Option<&syn::Path> {
628         self.partial_ord.compare_with.as_ref()
629     }
630 
ord_compare_with(&self) -> Option<&syn::Path>631     pub fn ord_compare_with(&self) -> Option<&syn::Path> {
632         self.ord.compare_with.as_ref()
633     }
634 
ignore_partial_eq(&self) -> bool635     pub fn ignore_partial_eq(&self) -> bool {
636         self.partial_eq.ignore
637     }
638 
ignore_partial_ord(&self) -> bool639     pub fn ignore_partial_ord(&self) -> bool {
640         self.partial_ord.ignore
641     }
642 
ignore_ord(&self) -> bool643     pub fn ignore_ord(&self) -> bool {
644         self.ord.ignore
645     }
646 }
647 
648 /// Represent an attribute.
649 ///
650 /// We only have a limited set of possible attributes:
651 ///
652 /// * `#[derivative(Debug)]` is represented as `(Debug, [])`;
653 /// * `#[derivative(Debug="foo")]` is represented as `(Debug, [(None, Some("foo"))])`;
654 /// * `#[derivative(Debug(foo="bar")]` is represented as `(Debug, [(Some(foo), Some("bar"))])`.
655 struct MetaItem<'a>(
656     &'a syn::Ident,
657     Vec<(Option<&'a syn::Ident>, Option<&'a syn::LitStr>)>,
658 );
659 
660 /// Parse an arbitrary item for our limited `MetaItem` subset.
read_items<'a>(item: &'a syn::NestedMeta, errors: &mut proc_macro2::TokenStream) -> Result<MetaItem<'a>, ()>661 fn read_items<'a>(item: &'a syn::NestedMeta, errors: &mut proc_macro2::TokenStream) -> Result<MetaItem<'a>, ()> {
662     let item = match *item {
663         syn::NestedMeta::Meta(ref item) => item,
664         syn::NestedMeta::Lit(ref lit) => {
665             errors.extend(quote_spanned! {lit.span()=>
666                 compile_error!("expected meta-item but found literal");
667             });
668 
669             return Err(());
670         }
671     };
672     match *item {
673         syn::Meta::Path(ref path) => match path.get_ident() {
674             Some(name) => Ok(MetaItem(name, Vec::new())),
675             None => {
676                 errors.extend(quote_spanned! {path.span()=>
677                     compile_error!("expected derivative attribute to be a string, but found a path");
678                 });
679 
680                 Err(())
681             }
682         },
683         syn::Meta::List(syn::MetaList {
684             ref path,
685             nested: ref values,
686             ..
687         }) => {
688             let values = values
689                 .iter()
690                 .map(|value| {
691                     if let syn::NestedMeta::Meta(syn::Meta::NameValue(syn::MetaNameValue {
692                         ref path,
693                         lit: ref value,
694                         ..
695                     })) = *value
696                     {
697                         let (name, value) = ensure_str_lit(&path, &value, errors)?;
698 
699                         Ok((Some(name), Some(value)))
700                     } else {
701                         errors.extend(quote_spanned! {value.span()=>
702                             compile_error!("expected named value");
703                         });
704 
705                         Err(())
706                     }
707                 })
708                 .collect::<Result<_, _>>()?;
709 
710             let name = match path.get_ident() {
711                 Some(name) => name,
712                 None => {
713                     errors.extend(quote_spanned! {path.span()=>
714                         compile_error!("expected derivative attribute to be a string, but found a path");
715                     });
716 
717                     return Err(());
718                 }
719             };
720 
721             Ok(MetaItem(name, values))
722         }
723         syn::Meta::NameValue(syn::MetaNameValue {
724             ref path,
725             lit: ref value,
726             ..
727         }) => {
728             let (name, value) = ensure_str_lit(&path, &value, errors)?;
729 
730             Ok(MetaItem(name, vec![(None, Some(value))]))
731         }
732     }
733 }
734 
735 /// Filter the `derivative` items from an attribute.
derivative_attribute( meta: syn::parse::Result<syn::Meta>, errors: &mut proc_macro2::TokenStream, ) -> Option<syn::punctuated::Punctuated<syn::NestedMeta, syn::token::Comma>>736 fn derivative_attribute(
737     meta: syn::parse::Result<syn::Meta>,
738     errors: &mut proc_macro2::TokenStream,
739 ) -> Option<syn::punctuated::Punctuated<syn::NestedMeta, syn::token::Comma>> {
740     match meta {
741         Ok(syn::Meta::List(syn::MetaList {
742             path, nested: mis, ..
743         })) => {
744             if path
745                 .get_ident()
746                 .map_or(false, |ident| ident == "derivative")
747             {
748                 Some(mis)
749             } else {
750                 None
751             }
752         }
753         Ok(_) => None,
754         Err(e) => {
755             let message = format!("invalid attribute: {}", e);
756             errors.extend(quote_spanned! {e.span()=>
757                 compile_error!(#message);
758             });
759 
760             None
761         }
762     }
763 }
764 
765 /// Parse an item value as a boolean. Accepted values are the string literal `"true"` and
766 /// `"false"`. The `default` parameter specifies what the value of the boolean is when only its
767 /// name is specified (eg. `Debug="ignore"` is equivalent to `Debug(ignore="true")`). The `name`
768 /// parameter is used for error reporting.
parse_boolean_meta_item( item: Option<&syn::LitStr>, default: bool, name: &str, errors: &mut proc_macro2::TokenStream, ) -> bool769 fn parse_boolean_meta_item(
770     item: Option<&syn::LitStr>,
771     default: bool,
772     name: &str,
773     errors: &mut proc_macro2::TokenStream,
774 ) -> bool {
775     if let Some(item) = item.as_ref() {
776         match item.value().as_ref() {
777             "true" => true,
778             "false" => false,
779             val => {
780                 if val == name {
781                     true
782                 } else {
783                     let message = format!(
784                         r#"expected `"true"` or `"false"` for `{}`, got `{}`"#,
785                         name, val
786                     );
787                     errors.extend(quote_spanned! {item.span()=>
788                         compile_error!(#message);
789                     });
790 
791                     default
792                 }
793             }
794         }
795     } else {
796         default
797     }
798 }
799 
800 /// Parse a `bound` item.
parse_bound( opt_bounds: &mut Option<Vec<syn::WherePredicate>>, value: Option<&syn::LitStr>, errors: &mut proc_macro2::TokenStream, )801 fn parse_bound(
802     opt_bounds: &mut Option<Vec<syn::WherePredicate>>,
803     value: Option<&syn::LitStr>,
804     errors: &mut proc_macro2::TokenStream,
805 ) {
806     let bound = value.expect("`bound` needs a value");
807     let bound_value = bound.value();
808 
809     *opt_bounds = if !bound_value.is_empty() {
810         let where_string = syn::LitStr::new(&format!("where {}", bound_value), bound.span());
811 
812         let bounds = parse_str_lit::<syn::WhereClause>(&where_string, errors)
813             .map(|wh| wh.predicates.into_iter().collect());
814 
815         match bounds {
816             Ok(bounds) => Some(bounds),
817             Err(_) => {
818                 errors.extend(quote_spanned! {where_string.span()=>
819                     compile_error!("could not parse bound");
820                 });
821 
822                 None
823             }
824         }
825     } else {
826         Some(vec![])
827     };
828 }
829 
parse_str_lit<T>(value: &syn::LitStr, errors: &mut proc_macro2::TokenStream) -> Result<T, ()> where T: syn::parse::Parse,830 fn parse_str_lit<T>(value: &syn::LitStr, errors: &mut proc_macro2::TokenStream) -> Result<T, ()>
831 where
832     T: syn::parse::Parse,
833 {
834     match value.parse() {
835         Ok(value) => Ok(value),
836         Err(e) => {
837             let message = format!("could not parse string literal: {}", e);
838             errors.extend(quote_spanned! {value.span()=>
839                 compile_error!(#message);
840             });
841             Err(())
842         }
843     }
844 }
845 
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), ()>846 fn ensure_str_lit<'a>(
847     attr_path: &'a syn::Path,
848     lit: &'a syn::Lit,
849     errors: &mut proc_macro2::TokenStream,
850 ) -> Result<(&'a syn::Ident, &'a syn::LitStr), ()> {
851     let attr_name = match attr_path.get_ident() {
852         Some(attr_name) => attr_name,
853         None => {
854             errors.extend(quote_spanned! {attr_path.span()=>
855                 compile_error!("expected derivative attribute to be a string, but found a path");
856             });
857             return Err(());
858         }
859     };
860 
861     if let syn::Lit::Str(ref lit) = *lit {
862         Ok((attr_name, lit))
863     } else {
864         let message = format!(
865             "expected derivative {} attribute to be a string: `{} = \"...\"`",
866             attr_name, attr_name
867         );
868         errors.extend(quote_spanned! {lit.span()=>
869             compile_error!(#message);
870         });
871         Err(())
872     }
873 }
874