1use std::borrow::Cow;
2use std::collections::{HashMap, HashSet};
3use std::fmt::Display;
4use std::iter;
5use std::ops::Range;
6
7use collection_literals::hash;
8use interpolator::{format, Formattable};
9use manyhow::{bail, error_message, manyhow, span_range, ErrorMessage, Result};
10use proc_macro2::{Literal, Span, TokenStream};
11use proc_macro_utils::{TokenParser, TokenStream2Ext};
12use quote::{format_ident, ToTokens};
13use quote_use::quote_use as quote;
14use syn::spanned::Spanned;
15use syn::{DataStruct, DeriveInput, Field, Fields, Generics, Ident, LitStr, Type, Visibility};
16
17const ATTRIBUTE_IDENTS: &[&str] = &["from_attr", "attribute", "attr"];
18
19#[allow(clippy::large_enum_variant)]
20enum StructError {
21 Generic(FormatString),
22 Specific(StructErrorSpecific),
23}
24
25struct FormatString {
26 format: Cow<'static, str>,
27 span: Span,
28 default: bool,
29}
30
31impl<T: Into<Cow<'static, str>>> From<T> for FormatString {
32 fn from(value: T) -> Self {
33 Self {
34 format: value.into(),
35 span: Span::call_site(),
36 default: true,
37 }
38 }
39}
40
41impl FormatString {
42 fn format(&self, values: HashMap<&str, Formattable>) -> Result<LitStr> {
43 Ok(LitStr::new(
44 &format(&self.format, &values).map_err(|e| error_message!(self.span, "{e}"))?,
45 self.span,
46 ))
47 }
48
49 fn parse(parser: &mut TokenParser) -> Option<Self> {
50 Some(Self {
51 span: parser.span(),
52 format: parser.next_string()?.into(),
53 default: false,
54 })
55 }
56}
57
58impl StructError {
59 fn duplicate_field(&self) -> &FormatString {
60 match self {
61 StructError::Generic(g) => g,
62 StructError::Specific(s) => &s.duplicate_field,
63 }
64 }
65
66 fn missing_field(&self) -> &FormatString {
67 match self {
68 StructError::Generic(g) => g,
69 StructError::Specific(s) => &s.missing_field,
70 }
71 }
72
73 fn field_help(&self) -> Option<&FormatString> {
74 if let StructError::Specific(s) = self {
75 Some(&s.field_help)
76 } else {
77 None
78 }
79 }
80
81 fn conflict(&self) -> &FormatString {
82 match self {
83 StructError::Generic(g) => g,
84 StructError::Specific(s) => &s.conflict,
85 }
86 }
87
88 fn unknown_field(&self) -> &FormatString {
89 match self {
90 StructError::Generic(g) => g,
91 StructError::Specific(s) => &s.unknown_field,
92 }
93 }
94
95 fn unknown_field_single(&self) -> &FormatString {
96 match self {
97 StructError::Generic(g) => g,
98 StructError::Specific(s) => &s.unknown_field_single,
99 }
100 }
101
102 fn unknown_field_empty(&self) -> &FormatString {
103 match self {
104 StructError::Generic(g) => g,
105 StructError::Specific(s) => &s.unknown_field_empty,
106 }
107 }
108
109 fn unknown_field_error(&self, fields: &[AttrField]) -> Result<LitStr> {
110 let fields: Vec<_> = fields
111 .iter()
112 .filter(|field| !field.positional)
113 .map(|field| Formattable::display(&field.ident))
114 .collect();
115 match fields.len() {
116 0 => self.unknown_field_empty().format(HashMap::new()),
117 1 => self
118 .unknown_field_single()
119 .format(hash!("expected_field" => fields[0])),
120 _ => self
121 .unknown_field()
122 .format(hash!("expected_fields" => Formattable::iter(&fields))),
123 }
124 }
125}
126
127struct StructErrorSpecific {
128 unknown_field: FormatString,
130 unknown_field_single: FormatString,
132 unknown_field_empty: FormatString,
133 duplicate_field: FormatString,
135 missing_field: FormatString,
137 field_help: FormatString,
139 conflict: FormatString,
141}
142
143impl Default for StructErrorSpecific {
144 fn default() -> Self {
145 Self {
146 unknown_field_empty: "expected empty attribute".into(),
147 unknown_field_single: "expected supported field `{expected_field}`".into(),
148 unknown_field: "supported fields are {expected_fields:i..-1(`{}`)(, )} and \
149 `{expected_fields:i-1}`"
150 .into(),
151 duplicate_field: "`{field}` is specified multiple times".into(),
152 missing_field: "required `{field}` is not specified".into(),
153 field_help: "try `#[{attribute}({field}{open_or_eq}{example}{close_or_empty})]`".into(),
154 conflict: "`{first}` conflicts with mutually exclusive `{second}`".into(),
155 }
156 }
157}
158
159struct StructAttrs {
167 ident: Option<Ident>,
168 aliases: Vec<String>,
169 error: StructError,
170 }
172
173impl StructAttrs {
174 fn from_attrs(
175 struct_ident: &Ident,
176 attrs: impl IntoIterator<Item = syn::Attribute>,
177 ) -> Result<Self> {
178 const VALID_FORMAT: &str = r#"expected `#[attribute(ident=attribute_name/!ident, aliases=[alias1, alias2], error="..", error(unknown_field="..", unknown_field_single="..", unknown_field_empty="..", duplicate_field="..", missing_field="..", field_help=".."))]`"#;
179
180 let mut ident_span: Option<Range<Span>> = None;
181 let mut ident: Option<Ident> = None;
182 let mut aliases: Vec<String> = vec![];
183 let mut error = StructError::Specific(Default::default());
184 for attr in attrs
186 .into_iter()
187 .filter(|attr| ATTRIBUTE_IDENTS.iter().any(|a| attr.path().is_ident(a)))
188 {
189 let parser = &mut attr
190 .meta
191 .require_list()
192 .map_err(|_| ErrorMessage::call_site(VALID_FORMAT))?
193 .tokens
194 .clone()
195 .parser();
196 while !parser.is_empty() {
197 if let Some(not) = parser.next_tt_not() {
198 if let Some(kw) = parser.next_keyword("ident") {
199 if let Some(ident_span) = ident_span {
200 bail!(
201 error_message!(ident_span, "ident is specified twice")
202 + error_message!(
203 not.span()..kw.span(),
204 "ident was already specified"
205 )
206 )
207 } else {
208 ident_span = Some(not.span()..kw.span());
209 }
210 }
211 } else {
212 let field = parser
213 .next_ident()
214 .ok_or_else(|| ErrorMessage::call_site(VALID_FORMAT))?;
215 match field.to_string().as_str() {
216 "ident" => {
217 parser
218 .next_tt_eq()
219 .ok_or_else(|| ErrorMessage::call_site(VALID_FORMAT))?;
220 ident = Some(
221 parser
222 .next_ident()
223 .ok_or_else(|| ErrorMessage::call_site(VALID_FORMAT))?,
224 );
225 if let Some(ident_span) = ident_span {
226 bail!(
227 error_message!(ident_span, "ident is specified twice")
228 + error_message!(
229 field.span()..ident.unwrap().span(),
230 "ident was already specified"
231 )
232 )
233 }
234 }
235 "aliases" => {
236 parser
237 .next_tt_eq()
238 .ok_or_else(|| ErrorMessage::call_site(VALID_FORMAT))?;
239 let mut parser = parser
240 .next_bracketed()
241 .ok_or_else(|| ErrorMessage::call_site(VALID_FORMAT))?
242 .stream()
243 .parser();
244 aliases.extend(iter::from_fn(|| {
245 _ = parser.next_tt_comma();
246 parser.next_ident().map(|t| t.to_string())
247 }));
248 if !parser.is_empty() {
249 bail!("{VALID_FORMAT}")
250 }
251 }
252 "error" => {
253 if parser.next_tt_eq().is_some() {
254 error = StructError::Generic(
255 FormatString::parse(parser)
256 .ok_or_else(|| ErrorMessage::call_site(VALID_FORMAT))?,
257 );
258 } else {
259 let parser = &mut parser
260 .next_parenthesized()
261 .ok_or_else(|| ErrorMessage::call_site(VALID_FORMAT))?
262 .stream()
263 .parser();
264 let error = if let StructError::Specific(error) = &mut error {
265 error
266 } else {
267 error = StructError::Specific(Default::default());
268 if let StructError::Specific(error) = &mut error {
269 error
270 } else {
271 unreachable!()
272 }
273 };
274 while !parser.is_empty() {
275 let field = parser
276 .next_ident()
277 .ok_or_else(|| ErrorMessage::call_site(VALID_FORMAT))?;
278 let mut string = |f: &mut _| -> Result<()> {
279 parser
280 .next_tt_eq()
281 .ok_or_else(|| ErrorMessage::call_site(VALID_FORMAT))?;
282 *f = FormatString::parse(parser)
283 .ok_or_else(|| ErrorMessage::call_site(VALID_FORMAT))?;
284 Ok(())
285 };
286 match field.to_string().as_str() {
287 "unknown_field" => string(&mut error.unknown_field),
288 "unknown_field_empty" => {
289 string(&mut error.unknown_field_empty)
290 }
291 "unknown_field_single" => {
292 string(&mut error.unknown_field_single)
293 }
294 "duplicate_field" => string(&mut error.duplicate_field),
295 "missing_field" => string(&mut error.missing_field),
296 "field_help" => string(&mut error.field_help),
297 "conflict" => string(&mut error.conflict),
298 _ => bail!(field, "{VALID_FORMAT}"),
299 }?;
300 _ = parser.next_tt_comma();
301 }
302 }
303 }
304 _ => bail!(field, "{VALID_FORMAT}"),
318 }
319 }
320 _ = parser.next_tt_comma();
321 }
322 }
323
324 if ident_span.is_none() && ident.is_none() {
325 let ident_string = struct_ident.to_string();
326 let mut out = String::with_capacity(ident_string.len());
327 let mut ident_string = ident_string.chars();
328
329 out.extend(ident_string.next().into_iter().flat_map(char::to_lowercase));
330 for c in ident_string {
331 if c.is_uppercase() {
332 out.push('_');
333 out.extend(c.to_lowercase());
334 } else {
335 out.push(c);
336 }
337 }
338
339 ident = Some(Ident::new(&out, struct_ident.span()));
340 }
341
342 Ok(Self {
343 ident,
344 aliases,
345 error,
346 })
348 }
349}
350
351struct FieldAttrs {
352 optional: bool,
353 default: Option<TokenStream>,
354 conflicts: Vec<Ident>,
356 example: Option<String>,
357 positional: bool,
358}
359
360impl FieldAttrs {
361 fn from_attrs(attrs: impl IntoIterator<Item = syn::Attribute>) -> Result<Self> {
362 const VALID_FORMAT: &str = r#"expected `#[attribute(optional, positional, default=1+5, conflicts=[a, b], example="22")]`"#;
363
364 let mut optional = false;
365 let mut default: Option<TokenStream> = None;
366 let mut conflicts: Vec<Ident> = Vec::new();
368 let mut example: Option<String> = None;
369 let mut positional = false;
370
371 for attr in attrs
372 .into_iter()
373 .filter(|attr| ATTRIBUTE_IDENTS.iter().any(|a| attr.path().is_ident(a)))
374 {
375 let mut parser = attr
376 .meta
377 .require_list()
378 .map_err(|e| error_message!(e.span(), "{VALID_FORMAT}"))?
379 .tokens
380 .clone()
381 .parser();
382 while !parser.is_empty() {
383 let field = parser
384 .next_ident()
385 .ok_or_else(|| error_message!(parser.next(), "{VALID_FORMAT}"))?;
386 match field.to_string().as_str() {
387 "optional" => optional = true,
388 "positional" => positional = true,
389 "default" => {
390 parser
391 .next_tt_eq()
392 .ok_or_else(|| error_message!(parser.next(), "{VALID_FORMAT}"))?;
393 default = Some(
394 parser
395 .next_expression()
396 .ok_or_else(|| error_message!(parser.next(), "{VALID_FORMAT}"))?,
397 );
398 optional = true;
399 }
400 "example" => {
401 parser
402 .next_tt_eq()
403 .ok_or_else(|| error_message!(parser.next(), "{VALID_FORMAT}"))?;
404 example = Some(
406 parser
407 .next_string()
408 .ok_or_else(|| error_message!(parser.next(), "{VALID_FORMAT}"))?,
409 );
410 }
411 "conflicts" => {
417 parser
418 .next_tt_eq()
419 .ok_or_else(|| error_message!(parser.next(), "{VALID_FORMAT}"))?;
420 let mut parser = parser
421 .next_bracketed()
422 .ok_or_else(|| error_message!(parser.next(), "{VALID_FORMAT}"))?
423 .stream()
424 .parser();
425 conflicts.extend(iter::from_fn(|| {
426 let ident = parser.next_ident();
427 _ = parser.next_tt_comma();
428 ident
429 }));
430 if !parser.is_empty() {
431 bail!(parser.next(), "{VALID_FORMAT}")
432 }
433 }
434 _ => bail!(field, "{VALID_FORMAT}"),
435 }
436 _ = parser.next_tt_comma();
437 }
438 }
439 Ok(Self {
440 optional,
441 default,
442 conflicts,
444 example,
445 positional,
446 })
447 }
448}
449#[derive(Default)]
452struct Conflicts(HashSet<(Ident, Ident)>);
453impl Conflicts {
454 fn insert(&mut self, a: Ident, b: Ident) {
455 if a < b {
456 self.0.insert((a, b));
457 } else {
458 self.0.insert((b, a));
459 }
460 }
461
462 fn to_tokens(&self, struct_error: &StructError) -> Result<TokenStream> {
463 let mut conflicts = self.0.iter().collect::<Vec<_>>();
464
465 conflicts.sort();
467
468 conflicts
469 .iter()
470 .map(|(a, b)| {
471 let af = Formattable::display(&a);
472 let bf = Formattable::display(&b);
473
474 let error_a_to_b = struct_error
475 .conflict()
476 .format(hash!("first" => af, "second" => bf))?;
477
478 let error_b_to_a = struct_error
479 .conflict()
480 .format(hash!("first" => bf, "second" => af))?;
481
482 Ok(quote! {
483 # use ::attribute_derive::__private::proc_macro2;
484 # use ::attribute_derive::__private::syn::{Error, Spanned};
485 if let (Some(__a), Some(__b)) = (&__partial.#a, &__partial.#b) {
486 if let Some(__joined_span) = __a.error_span().join(__b.error_span()) {
487 return Err(Error::new(__joined_span, #error_a_to_b));
488 } else {
489 let mut __error = Error::new(__a.error_span(), #error_a_to_b);
490 __error.combine(Error::new(__b.error_span(), #error_b_to_a));
491 return Err(__error);
492 }
493 }
494 })
495 })
496 .collect()
497 }
498}
499
500enum IdentOrIdx {
501 Ident(Ident),
502 Idx(usize),
503}
504
505impl Display for IdentOrIdx {
506 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
507 match self {
508 IdentOrIdx::Ident(i) => write!(f, "{i}"),
509 IdentOrIdx::Idx(i) => write!(f, "{i}"),
510 }
511 }
512}
513
514impl ToTokens for IdentOrIdx {
515 fn to_tokens(&self, tokens: &mut TokenStream) {
516 match self {
517 IdentOrIdx::Ident(i) => i.to_tokens(tokens),
518 IdentOrIdx::Idx(i) => Literal::usize_unsuffixed(*i).to_tokens(tokens),
519 }
520 }
521}
522
523struct AttrField {
524 ident: IdentOrIdx,
525 duplicate: LitStr,
526 help: Option<String>,
527 missing: String,
528 default: Option<TokenStream>,
529 ty: Type,
530 positional: bool,
531}
532
533impl AttrField {
534 fn parse_fields(
535 input: impl IntoIterator<Item = Field>,
536 struct_error: &StructError,
537 attribute_ident: Option<Ident>,
538 ) -> Result<(Vec<AttrField>, Conflicts)> {
539 let mut conflicts = Conflicts::default();
540 Ok((
541 input
542 .into_iter()
543 .enumerate()
544 .map(
545 |(
546 idx,
547 Field {
548 attrs, ident, ty, ..
549 },
550 )| {
551 let field_name = ident
552 .as_ref()
553 .map_or_else(|| format!("positional_{idx}"), ToString::to_string);
554
555 let FieldAttrs {
556 optional,
557 default,
558 conflicts: field_conflicts,
559 example,
560 mut positional,
561 } = FieldAttrs::from_attrs(attrs)?;
562
563 positional |= ident.is_none();
564
565 for conflict in field_conflicts {
566 if positional {
567 bail!(
568 ident.map_or_else(
569 || span_range!(ty),
570 |ident| ident.span().span_range()
571 ),
572 "positional fields do not support conflicts"
573 )
574 }
575 conflicts.insert(
576 ident
577 .as_ref()
578 .expect("unnamed fields should be positional")
579 .clone(),
580 conflict,
581 );
582 }
583
584 let duplicate = struct_error
585 .duplicate_field()
586 .format(hash!("field" => Formattable::display(&field_name)))?;
587
588 let help = if let Some(help) = struct_error.field_help() {
589 if attribute_ident.is_none() && help.default {
590 None
591 } else {
592 let example = &example.as_deref().unwrap_or("...");
593 let mut context = hash!(
594 "field" => Formattable::display(&field_name),
595 "example" => Formattable::display(example),
596 "open_or_eq" => Formattable::display(&"{open_or_eq}"),
597 "close_or_empty" => Formattable::display(&"{close_or_empty}"));
598 if let Some(ident) = &attribute_ident {
599 context.insert("attribute", Formattable::display(ident));
600 }
601 Some(format!("\n\n= help: {}", help.format(context)?.value()))
602 }
603 } else {
604 None
605 };
606
607 let missing = struct_error
608 .missing_field()
609 .format(hash!("field" => Formattable::display(&field_name)))?
610 .value()
611 + help.as_deref().unwrap_or_default();
612
613 let default = if let Some(default) = default {
614 Some(default.to_token_stream())
615 } else if optional {
616 Some(quote!(<#ty as Default>::default()))
617 } else {
618 None
619 };
620
621 Ok(AttrField {
622 positional,
623 ident: ident.map_or(IdentOrIdx::Idx(idx), IdentOrIdx::Ident),
624 duplicate,
625 help,
626 missing,
627 default,
628 ty,
629 })
630 },
631 )
632 .collect::<Result<_>>()?,
633 conflicts,
634 ))
635 }
636
637 fn map_error(&self, ty: &Type) -> TokenStream {
638 self.help
639 .as_ref()
640 .map(|help| {
641 let fmt = format!("{{__error}}{help}{{open_or_eq:.0}}{{close_or_empty:.0}}");
644 let ty = quote!(<#ty as ::attribute_derive::parsing::AttributeNamed>);
645 quote! { .map_err(|__error| {
646 ::attribute_derive::__private::syn::Error::new(
647 __error.span(),
648 format!(#fmt,
649 open_or_eq=#ty::PREFERRED_OPEN_DELIMITER,
650 close_or_empty=#ty::PREFERRED_CLOSE_DELIMITER)
651 )
652 })}
653 })
654 .unwrap_or_default()
655 }
656
657 fn partial(&self) -> TokenStream {
658 let ty = &self.ty;
659 if let IdentOrIdx::Ident(ref ident) = self.ident {
660 if self.positional {
661 quote!(#ident: Option<::attribute_derive::parsing::SpannedValue<
662 <#ty as ::attribute_derive::parsing::AttributeBase>::Partial>>)
663 } else {
664 quote!(#ident: Option<::attribute_derive::parsing::Named<
665 ::attribute_derive::parsing::SpannedValue<
666 <#ty as ::attribute_derive::parsing::AttributeBase>::Partial>>>)
667 }
668 } else {
669 quote!(Option<::attribute_derive::parsing::SpannedValue<
670 <#ty as ::attribute_derive::parsing::AttributeBase>::Partial>>)
671 }
672 }
673
674 fn parse_positional(&self) -> Option<TokenStream> {
675 let Self {
676 ident,
677 ty,
678 positional,
679 ..
680 } = self;
681 positional.then(|| {
682 let parse_comma = parse_comma();
683 quote! {
685 # use attribute_derive::parsing::AttributePositional;
686 if let Some(__field) = <#ty as AttributePositional>::parse_positional(__input)? {
687 __partial.#ident = Some(__field);
688 #parse_comma;
689 }
690 }
691 })
692 }
693
694 fn parse_named(&self) -> Option<TokenStream> {
695 let Self {
696 ident,
697 ty,
698 positional,
699 duplicate,
700 ..
701 } = self;
702 (!positional).then(|| {
703 let parse_comma = parse_comma();
704 let map_error = self.map_error(ty);
705 let s_ident = ident.to_string();
706 quote! {
707 # use attribute_derive::parsing::{AttributeBase, AttributeNamed};
708 # use attribute_derive::from_partial::FromPartial;
709 if let Some(__field) =
710 <#ty as AttributeNamed>::parse_named(#s_ident, __input) #map_error?
711 {
712 let __name = __field.name;
713 __partial.#ident =
714 <#ty as FromPartial<<#ty as AttributeBase>::Partial>>::join(
715 std::mem::take(&mut __partial.#ident).map(|__v| __v.value),
716 __field.value,
717 #duplicate,
718 )?
719 .map(|__v| ::attribute_derive::parsing::Named {
720 name: __name,
721 value: __v,
722 });
723
724 #parse_comma;
725 continue;
726 }
727 }
728 })
729 }
730
731 fn assign_partial(&self) -> TokenStream {
732 let Self {
733 ident,
734 missing,
735 default,
736 ty,
737 ..
738 } = self;
739 let unwrap = default.as_ref().map_or_else(
740 || quote!(?),
741 |default| quote!(.unwrap_or_else(|_| #default)),
742 );
743 let fmt = format!("{missing}{{open_or_eq:.0}}{{close_or_empty:.0}}");
744 let attr_named = quote!(<#ty as ::attribute_derive::parsing::AttributeNamed>);
745 quote! {
746 #ident: <#ty as ::attribute_derive::from_partial::FromPartial<
747 <#ty as ::attribute_derive::parsing::AttributeBase>::Partial>>::from_option(
748 __partial.#ident.map(|__v| __v.value()),
749 &format!(#fmt, open_or_eq=#attr_named::PREFERRED_OPEN_DELIMITER,
750 close_or_empty=#attr_named::PREFERRED_CLOSE_DELIMITER)
751 )#unwrap
752 }
753 }
754
755 fn join_field(&self) -> TokenStream {
756 let Self {
757 ident,
758 ty,
759 duplicate,
760 ..
761 } = self;
762 let join = quote! {
763 __first.#ident = <#ty as ::attribute_derive::from_partial::FromPartial<
764 <#ty as ::attribute_derive::parsing::AttributeBase>::Partial>>::join(
765 __first_value, __second_value, #duplicate)?
766 };
767
768 if self.positional {
769 quote! {
770 if let Some(__second_value) = __second.#ident {
771 let __first_value = ::std::mem::take(&mut __first.#ident);
772 #join;
773 }
774 }
775 } else {
776 quote! {
777 if let Some(__second) = __second.#ident {
778 let (__first_name, __first_value) = if let Some(__first) =
779 ::std::mem::take(&mut __first.#ident) {
780 (Some(__first.name), Some(__first.value))
781 } else {(None, None)};
782 let __name = __first_name.unwrap_or(__second.name);
783 let __second_value = __second.value;
784 #join.map(|__v| ::attribute_derive::parsing::Named{name: __name, value: __v});
785 }
786
787 }
788 }
789 }
790}
791
792fn parse_comma() -> TokenStream {
793 quote! {
794 if __input.is_empty() {
795 return Ok(__partial);
796 } else {
797 <::attribute_derive::__private::syn::Token![,] as
798 ::attribute_derive::__private::syn::parse::Parse>::parse(__input)?;
799 }
800 }
801}
802
803fn partial_attribute(
804 partial: &Ident,
805 vis: &Visibility,
806 fields: &[AttrField],
807 generics: &Generics,
808) -> Result {
809 let Some(first_field) = fields.first() else {
810 return Ok(quote!(#[derive(Default)] struct #partial #generics {}));
811 };
812 let fields = fields.iter().map(AttrField::partial);
813 let fields = if matches!(first_field.ident, IdentOrIdx::Ident(_)) {
814 quote!({#(#fields),*})
815 } else {
816 quote!((#(#fields),*);)
817 };
818 Ok(quote! {
819 #[derive(Default)]
820 #vis struct #partial #generics #fields
821 })
822}
823
824#[manyhow(impl_fn)]
825#[deprecated = "use `FromAttr` instead"]
826#[proc_macro_derive(Attribute, attributes(attribute, attr, from_attr))]
827pub fn attribute_derive(input: DeriveInput) -> Result {
828 from_attr_derive_impl(input)
829}
830
831#[manyhow(impl_fn)]
832#[proc_macro_derive(FromAttr, attributes(attribute, attr, from_attr))]
833pub fn from_attr_derive(
834 DeriveInput {
835 attrs,
836 vis,
837 ident,
838 generics,
839 data,
840 ..
841 }: DeriveInput,
842) -> Result {
843 let partial_ident = &format_ident!("{ident}Partial");
844
845 let StructAttrs {
846 ident: attribute_ident,
847 mut aliases,
848 error: ref struct_error,
849 } = StructAttrs::from_attrs(&ident, attrs)?;
851
852 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
853
854 if let Some(ref attribute_ident) = attribute_ident {
855 aliases.insert(0, attribute_ident.to_string());
856 }
857
858 let attribute_ident_trait = (!aliases.is_empty())
859 .then(|| {
860 quote! {
861 # use attribute_derive::AttributeIdent;
862
863 impl #impl_generics AttributeIdent for #ident #ty_generics #where_clause {
864 const IDENTS: &'static [&'static str] = &[#(#aliases),*];
865 }
866 }
867 })
868 .unwrap_or_default();
869
870 let (fields, conflicts) = match data {
871 syn::Data::Struct(DataStruct {
872 fields: fields @ (Fields::Named(_) | Fields::Unnamed(_)),
873 ..
874 }) => AttrField::parse_fields(fields, struct_error, attribute_ident)?,
875 _ => bail!("only works on structs with fields"),
876 };
877
878 let conflicts = conflicts.to_tokens(struct_error)?;
879
880 let partial_struct = partial_attribute(partial_ident, &vis, &fields, &generics)?;
881
882 let error_invalid_name = struct_error.unknown_field_error(&fields)?;
883
884 let partial_fields = fields.iter().map(AttrField::assign_partial);
885 let join_fields = fields.iter().map(AttrField::join_field);
886
887 let from_attr = if fields.len() == 1 && fields[0].positional {
888 let AttrField { ref ty, .. } = fields[0];
890 quote! {
891 # use ::attribute_derive::FromAttr;
892 # use ::attribute_derive::parsing::SpannedValue;
893 # use ::attribute_derive::__private::syn::parse::{ParseStream, Parse};
894 # use ::attribute_derive::__private::syn::{Result, Error};
895 impl #impl_generics FromAttr for #ident #ty_generics #where_clause {
896 fn parse_partial(input: ParseStream) -> Result<Self::Partial> {
897 <#ty as FromAttr>::parse_partial(input)
898 .map(SpannedValue::call_site)
899 .map(Some)
900 .map(#partial_ident)
901 }
902 }
903
904 }
905 } else {
906 let parse_positionals: Vec<_> = fields
907 .iter()
908 .filter_map(AttrField::parse_positional)
909 .collect();
910 let parse_named: Vec<_> = fields.iter().filter_map(AttrField::parse_named).collect();
911 quote! {
912 # use ::attribute_derive::parsing::AttributeMeta;
913 # use ::attribute_derive::__private::syn::parse::{ParseStream, Parse};
914 # use ::attribute_derive::__private::syn::{Result, Error};
915 impl #impl_generics AttributeMeta for #ident #ty_generics #where_clause {
916 fn parse_inner(__input: ParseStream) -> Result<Self::Partial> {
917 let mut __partial = #partial_ident::default();
918 #(#parse_positionals)*
919 while !__input.is_empty() {
920 #(#parse_named)*
921 return Err(__input.error(#error_invalid_name));
922 }
923 Ok(__partial)
924 }
925 }
926 }
927 };
928 Ok(quote! {
929 # use ::attribute_derive::parsing::{AttributeBase, SpannedValue};
930 # use ::attribute_derive::from_partial::FromPartial;
931 # use ::attribute_derive::__private::syn::parse::{ParseStream, Parse};
932 # use ::attribute_derive::__private::syn::{Result, Error};
933 #[allow(clippy::field_reassign_with_default, remove_unnecessary_else)]
934 const _: () = {
935 #attribute_ident_trait
936 #partial_struct
937
938 impl #impl_generics AttributeBase for #ident #ty_generics #where_clause {
939 type Partial = #partial_ident #ty_generics;
940 }
941
942 #from_attr
943
944 impl #impl_generics Parse for #ident #ty_generics #where_clause {
945 fn parse(__input: ParseStream) -> Result<Self> {
946 <Self as ::attribute_derive::FromAttr>::parse_input(__input)
947 }
948 }
949
950 impl #impl_generics FromPartial<#partial_ident #ty_generics> for #ident #ty_generics
951 #where_clause {
952 fn from(__partial: #partial_ident #ty_generics) -> Result<Self> {
953 #conflicts
954 Ok(Self {
955 #(#partial_fields),*
956 })
957 }
958
959 fn from_option(__partial: Option<#partial_ident #ty_generics>, _: &str)
960 -> Result<Self> {
961 <Self as FromPartial<#partial_ident #ty_generics>>::from(
962 __partial.unwrap_or_default())
963 }
964
965 fn join(
966 __first: Option<SpannedValue<#partial_ident #ty_generics>>,
967 __second: SpannedValue<#partial_ident #ty_generics>,
968 _: &str)
969 -> Result<Option<SpannedValue<#partial_ident #ty_generics>>> {
970 let mut __first = __first.unwrap_or_default().value;
971 let __span = __second.span;
972 let __second = __second.value;
973 #(#join_fields;)*
974 Ok(Some(SpannedValue { span: __span, value: __first}))
975 }
976 }
977 };
978 })
979}