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