1use proc_macro2;
2use syn;
3use syn::spanned::Spanned;
4
5/// Represent the `derivative` attributes on the input type (`struct`/`enum`).
6#[derive(Debug, Default)]
7pub 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.
31pub 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.
54pub 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.
63pub 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.
70pub 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.
79pub 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.
88pub 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.
95pub 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.
102pub 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.
109pub 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.
118pub 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.
127pub 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.
136pub 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.
147pub 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.
156pub 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.
167pub 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.
178pub 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.
189pub 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
198macro_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
215macro_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
260impl Input {
261 /// Parse the `derivative` attributes on a type.
262 #[allow(clippy::cognitive_complexity)] // mostly macros
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
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
380 pub fn clone_from(&self) -> bool {
381 self.clone.as_ref().map_or(false, |d| d.clone_from)
382 }
383
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
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
396 pub fn debug_transparent(&self) -> bool {
397 self.debug.as_ref().map_or(false, |d| d.transparent)
398 }
399
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
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
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
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
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
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
436 pub fn partial_ord_on_enum(&self) -> bool {
437 self.partial_ord.as_ref().map_or(false, |d| d.on_enum)
438 }
439
440 pub fn ord_on_enum(&self) -> bool {
441 self.ord.as_ref().map_or(false, |d| d.on_enum)
442 }
443}
444
445impl Field {
446 /// Parse the `derivative` attributes on a type.
447 #[allow(clippy::cognitive_complexity)] // mostly macros
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
567 pub fn clone_bound(&self) -> Option<&[syn::WherePredicate]> {
568 self.clone.bounds.as_ref().map(Vec::as_slice)
569 }
570
571 pub fn clone_with(&self) -> Option<&syn::Path> {
572 self.clone.clone_with.as_ref()
573 }
574
575 pub fn copy_bound(&self) -> Option<&[syn::WherePredicate]> {
576 self.copy_bound.as_ref().map(Vec::as_slice)
577 }
578
579 pub fn debug_bound(&self) -> Option<&[syn::WherePredicate]> {
580 self.debug.bounds.as_ref().map(Vec::as_slice)
581 }
582
583 pub fn debug_format_with(&self) -> Option<&syn::Path> {
584 self.debug.format_with.as_ref()
585 }
586
587 pub fn ignore_debug(&self) -> bool {
588 self.debug.ignore
589 }
590
591 pub fn ignore_hash(&self) -> bool {
592 self.hash.ignore
593 }
594
595 pub fn default_bound(&self) -> Option<&[syn::WherePredicate]> {
596 self.default.bounds.as_ref().map(Vec::as_slice)
597 }
598
599 pub fn default_value(&self) -> Option<&proc_macro2::TokenStream> {
600 self.default.value.as_ref()
601 }
602
603 pub fn eq_bound(&self) -> Option<&[syn::WherePredicate]> {
604 self.eq_bound.as_ref().map(Vec::as_slice)
605 }
606
607 pub fn hash_bound(&self) -> Option<&[syn::WherePredicate]> {
608 self.hash.bounds.as_ref().map(Vec::as_slice)
609 }
610
611 pub fn hash_with(&self) -> Option<&syn::Path> {
612 self.hash.hash_with.as_ref()
613 }
614
615 pub fn partial_eq_bound(&self) -> Option<&[syn::WherePredicate]> {
616 self.partial_eq.bounds.as_ref().map(Vec::as_slice)
617 }
618
619 pub fn partial_ord_bound(&self) -> Option<&[syn::WherePredicate]> {
620 self.partial_ord.bounds.as_ref().map(Vec::as_slice)
621 }
622
623 pub fn ord_bound(&self) -> Option<&[syn::WherePredicate]> {
624 self.ord.bounds.as_ref().map(Vec::as_slice)
625 }
626
627 pub fn partial_eq_compare_with(&self) -> Option<&syn::Path> {
628 self.partial_eq.compare_with.as_ref()
629 }
630
631 pub fn partial_ord_compare_with(&self) -> Option<&syn::Path> {
632 self.partial_ord.compare_with.as_ref()
633 }
634
635 pub fn ord_compare_with(&self) -> Option<&syn::Path> {
636 self.ord.compare_with.as_ref()
637 }
638
639 pub fn ignore_partial_eq(&self) -> bool {
640 self.partial_eq.ignore
641 }
642
643 pub fn ignore_partial_ord(&self) -> bool {
644 self.partial_ord.ignore
645 }
646
647 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"))])`.
659struct 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.
665fn 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.
740fn 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: MetaList)) => Some(meta_list.nested),
749 Ok(_) => None,
750 Err(e: Error) => {
751 let message: String = format!("invalid attribute: {}", e);
752 errors.extend(iter: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.
765fn 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.
797fn 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: &LitStr = value.expect(msg:"`bound` needs a value");
803 let bound_value: String = bound.value();
804
805 *opt_bounds = if !bound_value.is_empty() {
806 let where_string: LitStr = syn::LitStr::new(&format!("where {}", bound_value), bound.span());
807
808 let bounds: Result, …> = parse_str_lit::<syn::WhereClause>(&where_string, errors)
809 .map(|wh: WhereClause| wh.predicates.into_iter().collect());
810
811 match bounds {
812 Ok(bounds: Vec) => Some(bounds),
813 Err(_) => {
814 errors.extend(iter: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
826fn parse_str_lit<T>(value: &syn::LitStr, errors: &mut proc_macro2::TokenStream) -> Result<T, ()>
827where
828 T: syn::parse::Parse,
829{
830 match value.parse() {
831 Ok(value: T) => Ok(value),
832 Err(e: Error) => {
833 let message: String = format!("could not parse string literal: {}", e);
834 errors.extend(iter:quote_spanned! {value.span()=>
835 compile_error!(#message);
836 });
837 Err(())
838 }
839 }
840}
841
842fn 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: &Ident = match attr_path.get_ident() {
848 Some(attr_name: &Ident) => attr_name,
849 None => {
850 errors.extend(iter: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: &LitStr) = *lit {
858 Ok((attr_name, lit))
859 } else {
860 let message: String = format!(
861 "expected derivative {} attribute to be a string: `{} = \"...\"`",
862 attr_name, attr_name
863 );
864 errors.extend(iter:quote_spanned! {lit.span()=>
865 compile_error!(#message);
866 });
867 Err(())
868 }
869}
870
871pub fn has_repr_packed_attr(attr: &syn::Attribute) -> bool {
872 if let Ok(attr: Meta) = attr.parse_meta() {
873 if attr.path().get_ident().map(|i: &Ident| i == "repr") == Some(true) {
874 if let syn::Meta::List(items: MetaList) = attr {
875 for item: NestedMeta in items.nested {
876 if let syn::NestedMeta::Meta(item: Meta) = item {
877 if item.path().get_ident().map(|i: &Ident| i == "packed") == Some(true) {
878 return true;
879 }
880 }
881 }
882 }
883 }
884 }
885
886 false
887}
888