1use proc_macro2::TokenStream;
2use quote::{format_ident, quote, ToTokens};
3use std::{collections::BTreeSet, fmt, mem};
4use syn::{
5 parenthesized,
6 parse::{Parse, ParseStream, Result},
7 punctuated::Punctuated,
8 token, Expr, Ident, Lit, LitBool, LitStr, Path, Type,
9};
10
11use crate::{ModuleName, SuffixKind, Transformation, UserInput};
12
13macro_rules! join_syn_error {
14 ($r1:expr, $r2:expr) => {
15 match ($r1, $r2) {
16 (Err(mut e1), Err(e2)) => {
17 e1.combine(e2);
18 Err(e1)
19 }
20 (Err(e), _) | (_, Err(e)) => Err(e),
21 (Ok(v1), Ok(v2)) => Ok((v1, v2)),
22 }
23 };
24}
25
26mod attr;
27mod enum_impl;
28mod field_container_impl;
29mod field_impl;
30mod named_struct_impl;
31mod tuple_struct_field_impl;
32mod tuple_struct_impl;
33mod variant_impl;
34
35pub(crate) use enum_impl::parse_enum;
36pub(crate) use named_struct_impl::parse_named_struct;
37pub(crate) use tuple_struct_impl::parse_tuple_struct;
38
39use attr::{ErrorForLocation as _, ErrorLocation};
40
41mod kw {
42 use syn::custom_keyword;
43
44 custom_keyword!(backtrace);
45 custom_keyword!(context);
46 custom_keyword!(crate_root);
47 custom_keyword!(display);
48 custom_keyword!(implicit);
49 custom_keyword!(module);
50 custom_keyword!(provide);
51 custom_keyword!(source);
52 custom_keyword!(transparent);
53 custom_keyword!(visibility);
54 custom_keyword!(whatever);
55
56 custom_keyword!(from);
57 custom_keyword!(exact);
58 custom_keyword!(generic);
59
60 custom_keyword!(name);
61 custom_keyword!(suffix);
62
63 custom_keyword!(opt);
64}
65
66#[derive(Default)]
67struct SynErrors(Option<syn::Error>);
68
69impl SynErrors {
70 fn push(&mut self, e: syn::Error) {
71 if let Some(prev_e) = &mut self.0 {
72 prev_e.combine(e);
73 } else {
74 self.0 = Some(e);
75 }
76 }
77
78 fn push_new(&mut self, span: impl quote::ToTokens, txt: impl fmt::Display) {
79 let e = syn::Error::new_spanned(span, txt);
80 self.push(e);
81 }
82
83 fn push_invalid<A>(&mut self, attr: A, location: ErrorLocation)
84 where
85 A: AttributeMeta,
86 {
87 self.push_new(attr, <A::Meta as attr::Attribute>::INVALID.on(location));
88 }
89
90 fn push_invalid_flag<A>(&mut self, attr: A, location: ErrorLocation)
91 where
92 A: FlagAttribute,
93 A::Meta: attr::FlagAttribute,
94 {
95 let i = if attr.has_arg() {
96 <A::Meta as attr::Attribute>::INVALID
97 } else {
98 <A::Meta as attr::FlagAttribute>::BASE_INVALID
99 };
100
101 self.push_new(attr, i.on(location));
102 }
103
104 fn finish<T>(self, value: T) -> syn::Result<T> {
105 match self.0 {
106 Some(e) => Err(e),
107 None => Ok(value),
108 }
109 }
110
111 fn assume_failed<T>(self) -> syn::Result<T> {
114 match self.0 {
115 Some(e) => Err(e),
116 None => unreachable!("No error recorded"),
117 }
118 }
119}
120
121#[derive(Default)]
122struct DocCommentBuilder {
123 reached_end_of_doc_comment: bool,
124 content: String,
125}
126
127impl DocCommentBuilder {
128 fn push(&mut self, line: &str) {
129 if self.reached_end_of_doc_comment {
133 return;
134 }
135
136 let trimmed = line.trim();
137 if trimmed.is_empty() {
138 self.reached_end_of_doc_comment = true;
139 return;
140 }
141
142 if !self.content.is_empty() {
143 self.content.push(' ');
144 }
145
146 self.content.push_str(trimmed);
147 }
148
149 fn finish(self) -> Option<crate::DocComment> {
150 let Self { content, .. } = self;
151 if content.is_empty() {
152 None
153 } else {
154 let shorthand_names = extract_field_names(&content)
155 .map(|n| quote::format_ident!("{}", n))
156 .collect();
157
158 Some(crate::DocComment {
159 content,
160 shorthand_names,
161 })
162 }
163 }
164}
165
166enum Attribute {
167 Backtrace(Backtrace),
168 ContextFlag(ContextFlag),
169 ContextName(ContextName),
170 ContextSuffix(ContextSuffix),
171 CrateRoot(CrateRoot),
172 Display(Display),
173 DocComment(DocComment),
174 Implicit(Implicit),
175 Module(Module),
176 ProvideFlag(ProvideFlag),
177 ProvideExpression(ProvideExpression),
178 SourceFlag(SourceFlag),
179 SourceFrom(SourceFrom),
180 Transparent(Transparent),
181 Visibility(Visibility),
182 Whatever(Whatever),
183}
184
185fn syn_attrs(
186 attrs: &[syn::Attribute],
187 errors: &mut SynErrors,
188 mut f: impl FnMut(&mut SynErrors, Attribute),
189) {
190 for attr in attrs {
191 if attr.path().is_ident("snafu") {
192 let attr_list = <Punctuated<NestedAttribute, token::Comma>>::parse_terminated;
193 let a = match attr.parse_args_with(attr_list) {
194 Ok(a) => a,
195 Err(e) => {
196 errors.push(e);
197 continue;
198 }
199 };
200
201 let mut f = |a| f(errors, a);
202
203 for pair in a.into_pairs() {
204 match pair.into_value() {
205 NestedAttribute::Backtrace(a) => f(Attribute::Backtrace(a)),
206 NestedAttribute::Context(a) => match a {
207 Context::Flag(a) => f(Attribute::ContextFlag(a)),
208 Context::Name(a) => f(Attribute::ContextName(a)),
209 Context::Suffix(a) => f(Attribute::ContextSuffix(a)),
210 },
211 NestedAttribute::CrateRoot(a) => f(Attribute::CrateRoot(a)),
212 NestedAttribute::Display(a) => f(Attribute::Display(a)),
213 NestedAttribute::Implicit(a) => f(Attribute::Implicit(a)),
214 NestedAttribute::Module(a) => f(Attribute::Module(a)),
215 NestedAttribute::Provide(a) => match a {
216 Provide::Flag(a) => f(Attribute::ProvideFlag(a)),
217 Provide::Expression(a) => f(Attribute::ProvideExpression(a)),
218 },
219 NestedAttribute::Source(a) => a.flatten(|a| match a {
220 Source::Flag(a) => f(Attribute::SourceFlag(a)),
221 Source::From(a) => f(Attribute::SourceFrom(a)),
222 }),
223 NestedAttribute::Transparent(a) => f(Attribute::Transparent(a)),
224 NestedAttribute::Visibility(a) => f(Attribute::Visibility(a)),
225 NestedAttribute::Whatever(a) => f(Attribute::Whatever(a)),
226 }
227 }
228 } else if attr.path().is_ident("doc") {
229 if let Ok(comment) = syn::parse2::<DocComment>(attr.meta.to_token_stream()) {
233 f(errors, Attribute::DocComment(comment));
234 }
235 }
236 }
237}
238
239struct AtMostOne<T, D> {
240 inner: AtMostOneInner<T>,
241 message: D,
242}
243
244impl<T, D> AtMostOne<T, D>
245where
246 D: fmt::Display,
247{
248 fn new(message: D) -> Self {
249 Self {
250 inner: Default::default(),
251 message,
252 }
253 }
254
255 fn push(&mut self, value: T)
256 where
257 T: quote::ToTokens,
258 {
259 let inner = mem::take(&mut self.inner);
260 self.inner = match inner {
261 AtMostOneInner::Empty => AtMostOneInner::One(value),
262
263 AtMostOneInner::One(_old_value) => {
264 let new_error = syn::Error::new_spanned(value, &self.message);
266 AtMostOneInner::Err(new_error)
267 }
268
269 AtMostOneInner::Err(mut error) => {
270 let new_error = syn::Error::new_spanned(value, &self.message);
271 error.combine(new_error);
272 AtMostOneInner::Err(error)
273 }
274 };
275 }
276
277 fn finish(self) -> syn::Result<Option<T>> {
278 match self.inner {
279 AtMostOneInner::Empty => Ok(None),
280 AtMostOneInner::One(value) => Ok(Some(value)),
281 AtMostOneInner::Err(error) => Err(error),
282 }
283 }
284
285 fn finish_default(self, errors: &mut SynErrors) -> Option<T> {
288 match self.finish() {
289 Ok(v) => v,
290 Err(e) => {
291 errors.push(e);
292 None
293 }
294 }
295 }
296
297 fn finish_exactly_one(self, span: impl quote::ToTokens) -> syn::Result<T> {
298 match self.inner {
299 AtMostOneInner::Empty => Err(syn::Error::new_spanned(span, &self.message)),
300
301 AtMostOneInner::One(value) => Ok(value),
302
303 AtMostOneInner::Err(error) => Err(error),
304 }
305 }
306}
307
308impl<T> AtMostOne<T, attr::ErrorWithLocation<attr::DuplicateAttribute>> {
309 fn attribute<A>(_attr: A, location: ErrorLocation) -> Self
310 where
311 A: attr::Attribute,
312 {
313 Self::new(A::DUPLICATE.on(location))
314 }
315}
316
317impl<T, D> Extend<T> for AtMostOne<T, D>
318where
319 T: quote::ToTokens,
320 D: fmt::Display,
321{
322 fn extend<I>(&mut self, iter: I)
323 where
324 I: IntoIterator<Item = T>,
325 {
326 for value in iter {
327 self.push(value);
328 }
329 }
330}
331
332enum AtMostOneInner<T> {
333 Empty,
334 One(T),
335 Err(syn::Error),
336}
337
338impl<T> Default for AtMostOneInner<T> {
339 fn default() -> Self {
340 AtMostOneInner::Empty
341 }
342}
343
344struct Sidecar<S, T>(S, T);
347
348impl<S, T> quote::ToTokens for Sidecar<S, T>
349where
350 S: quote::ToTokens,
351{
352 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
353 self.0.to_tokens(tokens);
354 }
355}
356
357enum NestedAttribute {
358 Backtrace(Backtrace),
359 Context(Context),
360 CrateRoot(CrateRoot),
361 Display(Display),
362 Implicit(Implicit),
363 Module(Module),
364 Provide(Provide),
365 Source(NestedSource),
366 Transparent(Transparent),
367 Visibility(Visibility),
368 Whatever(Whatever),
369}
370
371impl Parse for NestedAttribute {
372 fn parse(input: ParseStream) -> Result<Self> {
373 let lookahead = input.lookahead1();
374 if lookahead.peek(kw::backtrace) {
375 input.parse().map(NestedAttribute::Backtrace)
376 } else if lookahead.peek(kw::context) {
377 input.parse().map(NestedAttribute::Context)
378 } else if lookahead.peek(kw::crate_root) {
379 input.parse().map(NestedAttribute::CrateRoot)
380 } else if lookahead.peek(kw::display) {
381 input.parse().map(NestedAttribute::Display)
382 } else if lookahead.peek(kw::implicit) {
383 input.parse().map(NestedAttribute::Implicit)
384 } else if lookahead.peek(kw::module) {
385 input.parse().map(NestedAttribute::Module)
386 } else if lookahead.peek(kw::provide) {
387 input.parse().map(NestedAttribute::Provide)
388 } else if lookahead.peek(kw::source) {
389 input.parse().map(NestedAttribute::Source)
390 } else if lookahead.peek(kw::transparent) {
391 input.parse().map(NestedAttribute::Transparent)
392 } else if lookahead.peek(kw::visibility) {
393 input.parse().map(NestedAttribute::Visibility)
394 } else if lookahead.peek(kw::whatever) {
395 input.parse().map(NestedAttribute::Whatever)
396 } else {
397 Err(lookahead.error())
398 }
399 }
400}
401
402struct Backtrace {
403 backtrace_token: kw::backtrace,
404 arg: MaybeArg<LitBool>,
405}
406
407impl Parse for Backtrace {
408 fn parse(input: ParseStream) -> Result<Self> {
409 Ok(Self {
410 backtrace_token: input.parse()?,
411 arg: input.parse()?,
412 })
413 }
414}
415
416impl ToTokens for Backtrace {
417 fn to_tokens(&self, tokens: &mut TokenStream) {
418 self.backtrace_token.to_tokens(tokens);
419 self.arg.to_tokens(tokens);
420 }
421}
422
423enum Context {
424 Flag(ContextFlag),
425 Name(ContextName),
426 Suffix(ContextSuffix),
427}
428
429impl Parse for Context {
430 fn parse(input: ParseStream) -> Result<Self> {
431 let context_token = input.parse()?;
432 let arg = input.parse::<MaybeArg<ContextArg>>()?;
433
434 Ok(match arg {
435 MaybeArg::None => Context::Flag(ContextFlag {
436 context_token,
437 arg: MaybeArg::None,
438 }),
439
440 MaybeArg::Some {
441 paren_token,
442 content,
443 } => match content {
444 ContextArg::Flag { value } => Context::Flag(ContextFlag {
445 context_token,
446 arg: MaybeArg::Some {
447 paren_token,
448 content: value,
449 },
450 }),
451
452 ContextArg::Name {
453 name_token,
454 paren_token: inner_paren_token,
455 name,
456 } => Context::Name(ContextName {
457 context_token,
458 paren_token,
459 name_token,
460 inner_paren_token,
461 name,
462 }),
463
464 ContextArg::Suffix {
465 suffix_token,
466 paren_token: inner_paren_token,
467 suffix,
468 } => Context::Suffix(ContextSuffix {
469 context_token,
470 paren_token,
471 suffix_token,
472 inner_paren_token,
473 suffix,
474 }),
475 },
476 })
477 }
478}
479
480struct ContextFlag {
481 context_token: kw::context,
482 arg: MaybeArg<LitBool>,
483}
484
485impl ToTokens for ContextFlag {
486 fn to_tokens(&self, tokens: &mut TokenStream) {
487 self.context_token.to_tokens(tokens);
488 self.arg.to_tokens(tokens);
489 }
490}
491
492struct ContextName {
493 context_token: kw::context,
494 paren_token: token::Paren,
495 name_token: kw::name,
496 inner_paren_token: token::Paren,
497 name: Ident,
498}
499
500impl ToTokens for ContextName {
501 fn to_tokens(&self, tokens: &mut TokenStream) {
502 self.context_token.to_tokens(tokens);
503 self.paren_token.surround(tokens, |tokens| {
504 self.name_token.to_tokens(tokens);
505 self.inner_paren_token.surround(tokens, |tokens| {
506 self.name.to_tokens(tokens);
507 });
508 });
509 }
510}
511
512struct ContextSuffix {
513 context_token: kw::context,
514 paren_token: token::Paren,
515 suffix_token: kw::suffix,
516 inner_paren_token: token::Paren,
517 suffix: SuffixArg,
518}
519
520impl ToTokens for ContextSuffix {
521 fn to_tokens(&self, tokens: &mut TokenStream) {
522 self.context_token.to_tokens(tokens);
523 self.paren_token.surround(tokens, |tokens| {
524 self.suffix_token.to_tokens(tokens);
525 self.inner_paren_token.surround(tokens, |tokens| {
526 self.suffix.to_tokens(tokens);
527 });
528 });
529 }
530}
531
532enum ContextArg {
533 Flag {
534 value: LitBool,
535 },
536 Name {
537 name_token: kw::name,
538 paren_token: token::Paren,
539 name: Ident,
540 },
541 Suffix {
542 suffix_token: kw::suffix,
543 paren_token: token::Paren,
544 suffix: SuffixArg,
545 },
546}
547
548impl Parse for ContextArg {
549 fn parse(input: ParseStream) -> Result<Self> {
550 let lookahead = input.lookahead1();
551 if lookahead.peek(LitBool) {
552 Ok(ContextArg::Flag {
553 value: input.parse()?,
554 })
555 } else if lookahead.peek(kw::suffix) {
556 let content;
557 Ok(ContextArg::Suffix {
558 suffix_token: input.parse()?,
559 paren_token: parenthesized!(content in input),
560 suffix: content.parse()?,
561 })
562 } else if lookahead.peek(kw::name) {
563 let content;
564 Ok(ContextArg::Name {
565 name_token: input.parse()?,
566 paren_token: parenthesized!(content in input),
567 name: content.parse()?,
568 })
569 } else {
570 Err(lookahead.error())
571 }
572 }
573}
574
575enum SuffixArg {
576 Flag { value: LitBool },
577 Suffix { suffix: Ident },
578}
579
580impl SuffixArg {
581 fn into_suffix_kind(self) -> SuffixKind {
582 match self {
583 SuffixArg::Flag { value } => {
584 if value.value {
585 SuffixKind::Default
586 } else {
587 SuffixKind::None
588 }
589 }
590 SuffixArg::Suffix { suffix } => SuffixKind::Some(suffix),
591 }
592 }
593}
594
595impl Parse for SuffixArg {
596 fn parse(input: ParseStream) -> Result<Self> {
597 let lookahead = input.lookahead1();
598 if lookahead.peek(LitBool) {
599 Ok(SuffixArg::Flag {
600 value: input.parse()?,
601 })
602 } else if lookahead.peek(Ident) {
603 Ok(SuffixArg::Suffix {
604 suffix: input.parse()?,
605 })
606 } else {
607 Err(lookahead.error())
608 }
609 }
610}
611
612impl ToTokens for SuffixArg {
613 fn to_tokens(&self, tokens: &mut TokenStream) {
614 match self {
615 SuffixArg::Flag { value } => {
616 value.to_tokens(tokens);
617 }
618 SuffixArg::Suffix { suffix } => {
619 suffix.to_tokens(tokens);
620 }
621 }
622 }
623}
624
625struct CrateRoot {
626 crate_root_token: kw::crate_root,
627 paren_token: token::Paren,
628 arg: Path,
629}
630
631fn into_crate_root(crate_root: Option<CrateRoot>) -> UserInput {
632 match crate_root {
633 Some(cr) => Box::new(cr.arg),
634 None => Box::new(quote! { ::snafu }),
635 }
636}
637
638impl Parse for CrateRoot {
639 fn parse(input: ParseStream) -> Result<Self> {
640 let content;
641 Ok(Self {
642 crate_root_token: input.parse()?,
643 paren_token: parenthesized!(content in input),
644 arg: content.parse()?,
645 })
646 }
647}
648
649impl ToTokens for CrateRoot {
650 fn to_tokens(&self, tokens: &mut TokenStream) {
651 self.crate_root_token.to_tokens(tokens);
652 self.paren_token.surround(tokens, |tokens| {
653 self.arg.to_tokens(tokens);
654 });
655 }
656}
657
658struct Display {
659 display_token: kw::display,
660 paren_token: token::Paren,
661 args: Punctuated<Expr, token::Comma>,
662}
663
664impl Display {
665 fn into_display(self) -> crate::Display {
666 let exprs: Vec<_> = self.args.into_iter().collect();
667 let mut shorthand_names = BTreeSet::new();
668 let mut assigned_names = BTreeSet::new();
669
670 if let Some((Expr::Lit(l), args)) = exprs.split_first() {
674 if let Lit::Str(s) = &l.lit {
675 let format_str = s.value();
676 let names = extract_field_names(&format_str).map(|n| format_ident!("{}", n));
677 shorthand_names.extend(names);
678 }
679
680 for arg in args {
681 if let Expr::Assign(a) = arg {
682 if let Expr::Path(p) = &*a.left {
683 assigned_names.extend(p.path.get_ident().cloned());
684 }
685 }
686 }
687 }
688
689 crate::Display {
690 exprs,
691 shorthand_names,
692 assigned_names,
693 }
694 }
695}
696
697pub(crate) fn extract_field_names(mut s: &str) -> impl Iterator<Item = &str> {
698 std::iter::from_fn(move || loop {
699 let open_curly = s.find('{')?;
700 s = &s[open_curly + '{'.len_utf8()..];
701
702 if s.starts_with('{') {
703 s = &s['{'.len_utf8()..];
704 continue;
705 }
706
707 let end_curly = s.find('}')?;
708 let format_contents = &s[..end_curly];
709
710 let name = match format_contents.find(':') {
711 Some(idx) => &format_contents[..idx],
712 None => format_contents,
713 };
714
715 if name.is_empty() {
716 continue;
717 }
718
719 return Some(name);
720 })
721}
722
723impl Parse for Display {
724 fn parse(input: ParseStream) -> Result<Self> {
725 let content;
726 Ok(Self {
727 display_token: input.parse()?,
728 paren_token: parenthesized!(content in input),
729 args: Punctuated::parse_terminated(&content)?,
730 })
731 }
732}
733
734impl ToTokens for Display {
735 fn to_tokens(&self, tokens: &mut TokenStream) {
736 self.display_token.to_tokens(tokens);
737 self.paren_token.surround(tokens, |tokens| {
738 self.args.to_tokens(tokens);
739 });
740 }
741}
742
743struct DocComment {
744 _doc_ident: Ident,
745 _eq_token: token::Eq,
746 str: LitStr,
747}
748
749impl Parse for DocComment {
750 fn parse(input: ParseStream) -> Result<Self> {
751 Ok(Self {
752 _doc_ident: input.parse()?,
753 _eq_token: input.parse()?,
754 str: input.parse()?,
755 })
756 }
757}
758
759struct Implicit {
760 implicit_token: kw::implicit,
761 arg: MaybeArg<LitBool>,
762}
763
764impl Parse for Implicit {
765 fn parse(input: ParseStream) -> Result<Self> {
766 Ok(Self {
767 implicit_token: input.parse()?,
768 arg: input.parse()?,
769 })
770 }
771}
772
773impl ToTokens for Implicit {
774 fn to_tokens(&self, tokens: &mut TokenStream) {
775 self.implicit_token.to_tokens(tokens);
776 self.arg.to_tokens(tokens);
777 }
778}
779
780struct Module {
781 module_token: kw::module,
782 arg: MaybeArg<Ident>,
783}
784
785impl Module {
786 fn into_value(self) -> ModuleName {
787 match self.arg.into_option() {
788 None => ModuleName::Default,
789 Some(name) => ModuleName::Custom(name),
790 }
791 }
792}
793
794impl Parse for Module {
795 fn parse(input: ParseStream) -> Result<Self> {
796 Ok(Self {
797 module_token: input.parse()?,
798 arg: input.parse()?,
799 })
800 }
801}
802
803impl ToTokens for Module {
804 fn to_tokens(&self, tokens: &mut TokenStream) {
805 self.module_token.to_tokens(tokens);
806 self.arg.to_tokens(tokens);
807 }
808}
809
810enum Provide {
811 Flag(ProvideFlag),
812
813 Expression(ProvideExpression),
814}
815
816impl Parse for Provide {
817 fn parse(input: ParseStream) -> Result<Self> {
818 let provide_token = input.parse()?;
819 let arg = input.parse::<MaybeArg<ProvideArg>>()?;
820
821 Ok(match arg {
822 MaybeArg::None => Provide::Flag(ProvideFlag {
823 provide_token,
824 value: MaybeArg::None,
825 }),
826 MaybeArg::Some {
827 paren_token,
828 content,
829 } => match content {
830 ProvideArg::Flag { value } => Provide::Flag(ProvideFlag {
831 provide_token,
832 value: MaybeArg::Some {
833 paren_token,
834 content: value,
835 },
836 }),
837 ProvideArg::Expression {
838 flags,
839 ty,
840 arrow,
841 expr,
842 } => {
843 let p = ProvideExpression {
844 provide_token,
845 paren_token,
846 flags,
847 ty,
848 arrow,
849 expr,
850 };
851
852 Provide::Expression(p)
853 }
854 },
855 })
856 }
857}
858
859struct ProvideFlag {
860 provide_token: kw::provide,
861 value: MaybeArg<LitBool>,
862}
863
864impl ToTokens for ProvideFlag {
865 fn to_tokens(&self, tokens: &mut TokenStream) {
866 self.provide_token.to_tokens(tokens);
867 self.value.to_tokens(tokens);
868 }
869}
870
871struct ProvideExpression {
872 provide_token: kw::provide,
873 paren_token: token::Paren,
874 flags: ProvideFlags,
875 ty: Type,
876 arrow: token::FatArrow,
877 expr: Expr,
878}
879
880impl ProvideExpression {
881 fn into_provide(self) -> crate::Provide {
882 crate::Provide {
883 is_opt: self.flags.is_opt(),
884 is_ref: self.flags.is_ref(),
885 ty: self.ty,
886 expr: self.expr,
887 }
888 }
889}
890
891impl ToTokens for ProvideExpression {
892 fn to_tokens(&self, tokens: &mut TokenStream) {
893 self.provide_token.to_tokens(tokens);
894 self.paren_token.surround(tokens, |tokens| {
895 self.flags.to_tokens(tokens);
896 self.ty.to_tokens(tokens);
897 self.arrow.to_tokens(tokens);
898 self.expr.to_tokens(tokens);
899 });
900 }
901}
902
903enum ProvideArg {
904 Flag {
905 value: LitBool,
906 },
907 Expression {
908 flags: ProvideFlags,
909 ty: Type,
910 arrow: token::FatArrow,
911 expr: Expr,
912 },
913}
914
915impl Parse for ProvideArg {
916 fn parse(input: ParseStream) -> Result<Self> {
917 if input.peek(LitBool) {
918 Ok(ProvideArg::Flag {
919 value: input.parse()?,
920 })
921 } else {
922 Ok(ProvideArg::Expression {
923 flags: input.parse()?,
924 ty: input.parse()?,
925 arrow: input.parse()?,
926 expr: input.parse()?,
927 })
928 }
929 }
930}
931
932struct ProvideFlags(Punctuated<ProvideFlagInner, token::Comma>);
933
934impl ProvideFlags {
935 fn is_opt(&self) -> bool {
936 self.0.iter().any(ProvideFlagInner::is_opt)
937 }
938
939 fn is_ref(&self) -> bool {
940 self.0.iter().any(ProvideFlagInner::is_ref)
941 }
942}
943
944impl Parse for ProvideFlags {
945 fn parse(input: ParseStream) -> Result<Self> {
946 let mut flags = Punctuated::new();
947
948 while ProvideFlagInner::peek(input) {
949 flags.push_value(input.parse()?);
950 flags.push_punct(input.parse()?);
951 }
952
953 Ok(Self(flags))
954 }
955}
956
957impl ToTokens for ProvideFlags {
958 fn to_tokens(&self, tokens: &mut TokenStream) {
959 self.0.to_tokens(tokens)
960 }
961}
962
963enum ProvideFlagInner {
964 Opt(kw::opt),
965 Ref(token::Ref),
966}
967
968impl ProvideFlagInner {
969 fn peek(input: ParseStream) -> bool {
970 input.peek(kw::opt) || input.peek(token::Ref)
971 }
972
973 fn is_opt(&self) -> bool {
974 matches!(self, ProvideFlagInner::Opt(_))
975 }
976
977 fn is_ref(&self) -> bool {
978 matches!(self, ProvideFlagInner::Ref(_))
979 }
980}
981
982impl Parse for ProvideFlagInner {
983 fn parse(input: ParseStream) -> Result<Self> {
984 let lookahead = input.lookahead1();
985
986 if lookahead.peek(kw::opt) {
987 input.parse().map(ProvideFlagInner::Opt)
988 } else if lookahead.peek(token::Ref) {
989 input.parse().map(ProvideFlagInner::Ref)
990 } else {
991 Err(lookahead.error())
992 }
993 }
994}
995
996impl ToTokens for ProvideFlagInner {
997 fn to_tokens(&self, tokens: &mut TokenStream) {
998 match self {
999 ProvideFlagInner::Opt(v) => v.to_tokens(tokens),
1000 ProvideFlagInner::Ref(v) => v.to_tokens(tokens),
1001 }
1002 }
1003}
1004
1005enum Source {
1006 Flag(SourceFlag),
1007
1008 From(SourceFrom),
1009}
1010
1011struct SourceFlag {
1012 source_token: kw::source,
1013 value: MaybeArg<LitBool>,
1014}
1015
1016impl ToTokens for SourceFlag {
1017 fn to_tokens(&self, tokens: &mut TokenStream) {
1018 self.source_token.to_tokens(tokens);
1019 self.value.to_tokens(tokens);
1020 }
1021}
1022
1023#[derive(Clone)]
1024struct SourceFrom {
1025 source_token: kw::source,
1026 paren_token: token::Paren,
1027 value: SourceFromArg,
1028}
1029
1030fn into_transformation(
1031 source_from: Option<SourceFrom>,
1032 target_ty: Type,
1033 default_from_is_generic: bool,
1034) -> Transformation {
1035 match source_from {
1036 Some(SourceFrom { value, .. }) => match value.value {
1037 SourceFromValue::Exact(_) => Transformation::None {
1038 target_ty,
1039 from_is_generic: false,
1040 },
1041
1042 SourceFromValue::Generic(_) => Transformation::None {
1043 target_ty,
1044 from_is_generic: true,
1045 },
1046
1047 SourceFromValue::Transform(SourceFromTransform { r#type, expr, .. }) => {
1048 Transformation::Transform {
1049 source_ty: r#type,
1050 target_ty,
1051 expr,
1052 }
1053 }
1054 },
1055
1056 None => Transformation::None {
1057 target_ty,
1058 from_is_generic: default_from_is_generic,
1059 },
1060 }
1061}
1062
1063impl ToTokens for SourceFrom {
1064 fn to_tokens(&self, tokens: &mut TokenStream) {
1065 self.source_token.to_tokens(tokens);
1066 self.paren_token.surround(tokens, |tokens| {
1067 self.value.to_tokens(tokens);
1068 });
1069 }
1070}
1071
1072struct NestedSource {
1073 source_token: kw::source,
1074 args: MaybeArg<Punctuated<SourceArg, token::Comma>>,
1075}
1076
1077impl NestedSource {
1078 fn flatten(self, mut f: impl FnMut(Source)) {
1079 let source_token = self.source_token;
1080
1081 match self.args {
1082 MaybeArg::None => f(Source::Flag(SourceFlag {
1083 source_token,
1084 value: MaybeArg::None,
1085 })),
1086
1087 MaybeArg::Some {
1088 paren_token,
1089 content,
1090 } => {
1091 for sa in content {
1092 let s = match sa {
1093 SourceArg::Flag { value } => Source::Flag(SourceFlag {
1094 source_token,
1095 value: MaybeArg::Some {
1096 paren_token,
1097 content: value,
1098 },
1099 }),
1100 SourceArg::From(value) => Source::From(SourceFrom {
1101 source_token,
1102 paren_token,
1103 value,
1104 }),
1105 };
1106 f(s);
1107 }
1108 }
1109 }
1110 }
1111}
1112
1113impl Parse for NestedSource {
1114 fn parse(input: ParseStream) -> Result<Self> {
1115 Ok(Self {
1116 source_token: input.parse()?,
1117 args: MaybeArg::parse_with(input, Punctuated::parse_terminated)?,
1118 })
1119 }
1120}
1121
1122enum SourceArg {
1123 Flag { value: LitBool },
1124 From(SourceFromArg),
1125}
1126
1127impl Parse for SourceArg {
1128 fn parse(input: ParseStream) -> Result<Self> {
1129 let lookahead = input.lookahead1();
1130 if lookahead.peek(LitBool) {
1131 Ok(SourceArg::Flag {
1132 value: input.parse()?,
1133 })
1134 } else if lookahead.peek(kw::from) {
1135 input.parse().map(SourceArg::From)
1136 } else {
1137 Err(lookahead.error())
1138 }
1139 }
1140}
1141
1142#[derive(Clone)]
1143struct SourceFromArg {
1144 from_token: kw::from,
1145 paren_token: token::Paren,
1146 value: SourceFromValue,
1147}
1148
1149impl Parse for SourceFromArg {
1150 fn parse(input: ParseStream) -> Result<Self> {
1151 let content;
1152
1153 Ok(SourceFromArg {
1154 from_token: input.parse()?,
1155 paren_token: parenthesized!(content in input),
1156 value: content.parse()?,
1157 })
1158 }
1159}
1160
1161impl ToTokens for SourceFromArg {
1162 fn to_tokens(&self, tokens: &mut TokenStream) {
1163 self.from_token.to_tokens(tokens);
1164 self.paren_token.surround(tokens, |tokens| {
1165 self.value.to_tokens(tokens);
1166 });
1167 }
1168}
1169
1170#[derive(Clone)]
1171enum SourceFromValue {
1172 Exact(kw::exact),
1173
1174 Generic(kw::generic),
1175
1176 Transform(SourceFromTransform),
1177}
1178
1179impl Parse for SourceFromValue {
1180 fn parse(input: ParseStream) -> Result<Self> {
1181 if input.peek(kw::exact) {
1182 input.parse().map(Self::Exact)
1183 } else if input.peek(kw::generic) {
1184 input.parse().map(Self::Generic)
1185 } else {
1186 let span = input.span();
1193 let txt = "expected one of: `exact`, `generic` or a type followed by a comma and an expression";
1194 input.parse().map(Self::Transform).map_err(|e| {
1195 let mut e1 = syn::Error::new(span, txt);
1196 e1.combine(e);
1197 e1
1198 })
1199 }
1200 }
1201}
1202
1203impl ToTokens for SourceFromValue {
1204 fn to_tokens(&self, tokens: &mut TokenStream) {
1205 match self {
1206 SourceFromValue::Exact(exact) => exact.to_tokens(tokens),
1207 SourceFromValue::Generic(generic) => generic.to_tokens(tokens),
1208 SourceFromValue::Transform(transform) => transform.to_tokens(tokens),
1209 }
1210 }
1211}
1212
1213#[derive(Clone)]
1214struct SourceFromTransform {
1215 r#type: Type,
1216 comma_token: token::Comma,
1217 expr: Expr,
1218}
1219
1220impl Parse for SourceFromTransform {
1221 fn parse(input: ParseStream) -> Result<Self> {
1222 Ok(Self {
1223 r#type: input.parse()?,
1224 comma_token: input.parse()?,
1225 expr: input.parse()?,
1226 })
1227 }
1228}
1229
1230impl ToTokens for SourceFromTransform {
1231 fn to_tokens(&self, tokens: &mut TokenStream) {
1232 self.r#type.to_tokens(tokens);
1233 self.comma_token.to_tokens(tokens);
1234 self.expr.to_tokens(tokens);
1235 }
1236}
1237
1238struct Transparent {
1239 transparent_token: kw::transparent,
1240 arg: MaybeArg<LitBool>,
1241}
1242
1243impl Parse for Transparent {
1244 fn parse(input: ParseStream) -> Result<Self> {
1245 Ok(Self {
1246 transparent_token: input.parse()?,
1247 arg: input.parse()?,
1248 })
1249 }
1250}
1251
1252impl ToTokens for Transparent {
1253 fn to_tokens(&self, tokens: &mut TokenStream) {
1254 self.transparent_token.to_tokens(tokens);
1255 self.arg.to_tokens(tokens);
1256 }
1257}
1258
1259struct Visibility {
1260 visibility_token: kw::visibility,
1261 visibility: MaybeArg<syn::Visibility>,
1262}
1263
1264impl Visibility {
1265 fn into_arbitrary(self) -> Box<dyn ToTokens> {
1267 self.visibility
1269 .into_option()
1270 .map_or_else(super::private_visibility, |v| Box::new(v))
1271 }
1272}
1273
1274impl Parse for Visibility {
1275 fn parse(input: ParseStream) -> Result<Self> {
1276 Ok(Self {
1277 visibility_token: input.parse()?,
1278 visibility: input.parse()?,
1279 })
1280 }
1281}
1282
1283impl ToTokens for Visibility {
1284 fn to_tokens(&self, tokens: &mut TokenStream) {
1285 self.visibility_token.to_tokens(tokens);
1286 self.visibility.to_tokens(tokens);
1287 }
1288}
1289
1290struct Whatever {
1291 whatever_token: kw::whatever,
1292}
1293
1294impl Parse for Whatever {
1295 fn parse(input: ParseStream) -> Result<Self> {
1296 Ok(Self {
1297 whatever_token: input.parse()?,
1298 })
1299 }
1300}
1301
1302impl ToTokens for Whatever {
1303 fn to_tokens(&self, tokens: &mut TokenStream) {
1304 self.whatever_token.to_tokens(tokens);
1305 }
1306}
1307
1308enum MaybeArg<T> {
1309 None,
1310 Some {
1311 paren_token: token::Paren,
1312 content: T,
1313 },
1314}
1315
1316impl<T> MaybeArg<T> {
1317 fn to_option(&self) -> Option<&T> {
1318 match self {
1319 MaybeArg::None => None,
1320 MaybeArg::Some { content, .. } => Some(content),
1321 }
1322 }
1323
1324 fn into_option(self) -> Option<T> {
1325 match self {
1326 MaybeArg::None => None,
1327 MaybeArg::Some { content, .. } => Some(content),
1328 }
1329 }
1330
1331 fn parse_with<F>(input: ParseStream<'_>, parser: F) -> Result<Self>
1332 where
1333 F: FnOnce(ParseStream<'_>) -> Result<T>,
1334 {
1335 let lookahead = input.lookahead1();
1336 if lookahead.peek(token::Paren) {
1337 let content;
1338 Ok(MaybeArg::Some {
1339 paren_token: parenthesized!(content in input),
1340 content: parser(&content)?,
1341 })
1342 } else {
1343 Ok(MaybeArg::None)
1344 }
1345 }
1346}
1347
1348impl<T: Parse> Parse for MaybeArg<T> {
1349 fn parse(input: ParseStream) -> Result<Self> {
1350 Self::parse_with(input, Parse::parse)
1351 }
1352}
1353
1354impl<T: ToTokens> ToTokens for MaybeArg<T> {
1355 fn to_tokens(&self, tokens: &mut TokenStream) {
1356 if let MaybeArg::Some {
1357 paren_token,
1358 content,
1359 } = self
1360 {
1361 paren_token.surround(tokens, |tokens| {
1362 content.to_tokens(tokens);
1363 });
1364 }
1365 }
1366}
1367
1368trait AttributeMeta: quote::ToTokens {
1369 type Meta: attr::Attribute;
1370}
1371
1372trait FlagAttribute: AttributeMeta
1373where
1374 Self::Meta: attr::FlagAttribute,
1375{
1376 fn arg(&self) -> &MaybeArg<LitBool>;
1377
1378 fn has_arg(&self) -> bool {
1379 matches!(self.arg(), MaybeArg::Some { .. })
1380 }
1381
1382 fn is_enabled(&self) -> bool {
1383 self.arg().to_option().map_or(true, |v| v.value)
1384 }
1385}
1386
1387macro_rules! def_attributes {
1388 ($($name:ident),* $(,)?) => {
1389 $(
1390 impl AttributeMeta for $name {
1391 type Meta = attr::$name;
1392 }
1393 )*
1394 };
1395}
1396
1397def_attributes![
1398 Backtrace,
1399 ContextFlag,
1400 ContextName,
1401 ContextSuffix,
1402 CrateRoot,
1403 Display,
1404 Implicit,
1405 Module,
1406 ProvideExpression,
1407 ProvideFlag,
1408 SourceFlag,
1409 SourceFrom,
1410 Transparent,
1411 Visibility,
1412 Whatever,
1413];
1414
1415macro_rules! def_flag_attributes {
1416 ($(($name:ident, $arg:ident)),* $(,)?) => {
1417 $(
1418 impl FlagAttribute for $name {
1419 fn arg(&self) -> &MaybeArg<LitBool> {
1420 &self.$arg
1421 }
1422 }
1423 )*
1424 };
1425}
1426
1427def_flag_attributes![
1428 (Backtrace, arg),
1429 (ContextFlag, arg),
1430 (Implicit, arg),
1431 (ProvideFlag, value),
1432 (SourceFlag, value),
1433 (Transparent, arg),
1434];
1435
1436#[cfg(test)]
1437mod test {
1438 use super::*;
1439
1440 fn names(s: &str) -> Vec<&str> {
1441 extract_field_names(s).collect::<Vec<_>>()
1442 }
1443
1444 #[test]
1445 fn ignores_positional_arguments() {
1446 assert_eq!(names("{}"), [] as [&str; 0]);
1447 }
1448
1449 #[test]
1450 fn finds_named_argument() {
1451 assert_eq!(names("{a}"), ["a"]);
1452 }
1453
1454 #[test]
1455 fn finds_multiple_named_arguments() {
1456 assert_eq!(names("{a} {b}"), ["a", "b"]);
1457 }
1458
1459 #[test]
1460 fn ignores_escaped_braces() {
1461 assert_eq!(names("{{a}}"), [] as [&str; 0]);
1462 }
1463
1464 #[test]
1465 fn finds_named_arguments_around_escaped() {
1466 assert_eq!(names("{a} {{b}} {c}"), ["a", "c"]);
1467 }
1468
1469 #[test]
1470 fn ignores_format_spec() {
1471 assert_eq!(names("{a:?}"), ["a"]);
1472 }
1473}