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