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 self.0
464 .iter()
465 .map(|(a, b)| {
466 let af = Formattable::display(&a);
467 let bf = Formattable::display(&b);
468
469 let error_a_to_b = struct_error
470 .conflict()
471 .format(hash!("first" => af, "second" => bf))?;
472
473 let error_b_to_a = struct_error
474 .conflict()
475 .format(hash!("first" => bf, "second" => af))?;
476
477 Ok(quote! {
478 # use ::attribute_derive::__private::proc_macro2;
479 # use ::attribute_derive::__private::syn::{Error, Spanned};
480 if let (Some(__a), Some(__b)) = (&__partial.#a, &__partial.#b) {
481 if let Some(__joined_span) = __a.error_span().join(__b.error_span()) {
482 return Err(Error::new(__joined_span, #error_a_to_b));
483 } else {
484 let mut __error = Error::new(__a.error_span(), #error_a_to_b);
485 __error.combine(Error::new(__b.error_span(), #error_b_to_a));
486 return Err(__error);
487 }
488 }
489 })
490 })
491 .collect()
492 }
493}
494
495enum IdentOrIdx {
496 Ident(Ident),
497 Idx(usize),
498}
499
500impl Display for IdentOrIdx {
501 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
502 match self {
503 IdentOrIdx::Ident(i) => write!(f, "{i}"),
504 IdentOrIdx::Idx(i) => write!(f, "{i}"),
505 }
506 }
507}
508
509impl ToTokens for IdentOrIdx {
510 fn to_tokens(&self, tokens: &mut TokenStream) {
511 match self {
512 IdentOrIdx::Ident(i) => i.to_tokens(tokens),
513 IdentOrIdx::Idx(i) => Literal::usize_unsuffixed(*i).to_tokens(tokens),
514 }
515 }
516}
517
518struct AttrField {
519 ident: IdentOrIdx,
520 duplicate: LitStr,
521 help: Option<String>,
522 missing: String,
523 default: Option<TokenStream>,
524 ty: Type,
525 positional: bool,
526}
527
528impl AttrField {
529 fn parse_fields(
530 input: impl IntoIterator<Item = Field>,
531 struct_error: &StructError,
532 attribute_ident: Option<Ident>,
533 ) -> Result<(Vec<AttrField>, Conflicts)> {
534 let mut conflicts = Conflicts::default();
535 Ok((
536 input
537 .into_iter()
538 .enumerate()
539 .map(
540 |(
541 idx,
542 Field {
543 attrs, ident, ty, ..
544 },
545 )| {
546 let field_name = ident
547 .as_ref()
548 .map_or_else(|| format!("positional_{idx}"), ToString::to_string);
549
550 let FieldAttrs {
551 optional,
552 default,
553 conflicts: field_conflicts,
554 example,
555 mut positional,
556 } = FieldAttrs::from_attrs(attrs)?;
557
558 positional |= ident.is_none();
559
560 for conflict in field_conflicts {
561 if positional {
562 bail!(
563 ident.map_or_else(
564 || span_range!(ty),
565 |ident| ident.span().span_range()
566 ),
567 "positional fields do not support conflicts"
568 )
569 }
570 conflicts.insert(
571 ident
572 .as_ref()
573 .expect("unnamed fields should be positional")
574 .clone(),
575 conflict,
576 );
577 }
578
579 let duplicate = struct_error
580 .duplicate_field()
581 .format(hash!("field" => Formattable::display(&field_name)))?;
582
583 let help = if let Some(help) = struct_error.field_help() {
584 if attribute_ident.is_none() && help.default {
585 None
586 } else {
587 let example = &example.as_deref().unwrap_or("...");
588 let mut context = hash!(
589 "field" => Formattable::display(&field_name),
590 "example" => Formattable::display(example),
591 "open_or_eq" => Formattable::display(&"{open_or_eq}"),
592 "close_or_empty" => Formattable::display(&"{close_or_empty}"));
593 if let Some(ident) = &attribute_ident {
594 context.insert("attribute", Formattable::display(ident));
595 }
596 Some(format!("\n\n= help: {}", help.format(context)?.value()))
597 }
598 } else {
599 None
600 };
601
602 let missing = struct_error
603 .missing_field()
604 .format(hash!("field" => Formattable::display(&field_name)))?
605 .value()
606 + help.as_deref().unwrap_or_default();
607
608 let default = if let Some(default) = default {
609 Some(default.to_token_stream())
610 } else if optional {
611 Some(quote!(<#ty as Default>::default()))
612 } else {
613 None
614 };
615
616 Ok(AttrField {
617 positional,
618 ident: ident.map_or(IdentOrIdx::Idx(idx), IdentOrIdx::Ident),
619 duplicate,
620 help,
621 missing,
622 default,
623 ty,
624 })
625 },
626 )
627 .collect::<Result<_>>()?,
628 conflicts,
629 ))
630 }
631
632 fn map_error(&self, ty: &Type) -> TokenStream {
633 self.help
634 .as_ref()
635 .map(|help| {
636 let fmt = format!("{{__error}}{help}{{open_or_eq:.0}}{{close_or_empty:.0}}");
639 let ty = quote!(<#ty as ::attribute_derive::parsing::AttributeNamed>);
640 quote! { .map_err(|__error| {
641 ::attribute_derive::__private::syn::Error::new(
642 __error.span(),
643 format!(#fmt,
644 open_or_eq=#ty::PREFERRED_OPEN_DELIMITER,
645 close_or_empty=#ty::PREFERRED_CLOSE_DELIMITER)
646 )
647 })}
648 })
649 .unwrap_or_default()
650 }
651
652 fn partial(&self) -> TokenStream {
653 let ty = &self.ty;
654 if let IdentOrIdx::Ident(ref ident) = self.ident {
655 if self.positional {
656 quote!(#ident: Option<::attribute_derive::parsing::SpannedValue<
657 <#ty as ::attribute_derive::parsing::AttributeBase>::Partial>>)
658 } else {
659 quote!(#ident: Option<::attribute_derive::parsing::Named<
660 ::attribute_derive::parsing::SpannedValue<
661 <#ty as ::attribute_derive::parsing::AttributeBase>::Partial>>>)
662 }
663 } else {
664 quote!(Option<::attribute_derive::parsing::SpannedValue<
665 <#ty as ::attribute_derive::parsing::AttributeBase>::Partial>>)
666 }
667 }
668
669 fn parse_positional(&self) -> Option<TokenStream> {
670 let Self {
671 ident,
672 ty,
673 positional,
674 ..
675 } = self;
676 positional.then(|| {
677 let parse_comma = parse_comma();
678 quote! {
680 # use attribute_derive::parsing::AttributePositional;
681 if let Some(__field) = <#ty as AttributePositional>::parse_positional(__input)? {
682 __partial.#ident = Some(__field);
683 #parse_comma;
684 }
685 }
686 })
687 }
688
689 fn parse_named(&self) -> Option<TokenStream> {
690 let Self {
691 ident,
692 ty,
693 positional,
694 duplicate,
695 ..
696 } = self;
697 (!positional).then(|| {
698 let parse_comma = parse_comma();
699 let map_error = self.map_error(ty);
700 let s_ident = ident.to_string();
701 quote! {
702 # use attribute_derive::parsing::{AttributeBase, AttributeNamed};
703 # use attribute_derive::from_partial::FromPartial;
704 if let Some(__field) =
705 <#ty as AttributeNamed>::parse_named(#s_ident, __input) #map_error?
706 {
707 let __name = __field.name;
708 __partial.#ident =
709 <#ty as FromPartial<<#ty as AttributeBase>::Partial>>::join(
710 std::mem::take(&mut __partial.#ident).map(|__v| __v.value),
711 __field.value,
712 #duplicate,
713 )?
714 .map(|__v| ::attribute_derive::parsing::Named {
715 name: __name,
716 value: __v,
717 });
718
719 #parse_comma;
720 continue;
721 }
722 }
723 })
724 }
725
726 fn assign_partial(&self) -> TokenStream {
727 let Self {
728 ident,
729 missing,
730 default,
731 ty,
732 ..
733 } = self;
734 let unwrap = default.as_ref().map_or_else(
735 || quote!(?),
736 |default| quote!(.unwrap_or_else(|_| #default)),
737 );
738 let fmt = format!("{missing}{{open_or_eq:.0}}{{close_or_empty:.0}}");
739 let attr_named = quote!(<#ty as ::attribute_derive::parsing::AttributeNamed>);
740 quote! {
741 #ident: <#ty as ::attribute_derive::from_partial::FromPartial<
742 <#ty as ::attribute_derive::parsing::AttributeBase>::Partial>>::from_option(
743 __partial.#ident.map(|__v| __v.value()),
744 &format!(#fmt, open_or_eq=#attr_named::PREFERRED_OPEN_DELIMITER,
745 close_or_empty=#attr_named::PREFERRED_CLOSE_DELIMITER)
746 )#unwrap
747 }
748 }
749
750 fn join_field(&self) -> TokenStream {
751 let Self {
752 ident,
753 ty,
754 duplicate,
755 ..
756 } = self;
757 let join = quote! {
758 __first.#ident = <#ty as ::attribute_derive::from_partial::FromPartial<
759 <#ty as ::attribute_derive::parsing::AttributeBase>::Partial>>::join(
760 __first_value, __second_value, #duplicate)?
761 };
762
763 if self.positional {
764 quote! {
765 if let Some(__second_value) = __second.#ident {
766 let __first_value = ::std::mem::take(&mut __first.#ident);
767 #join;
768 }
769 }
770 } else {
771 quote! {
772 if let Some(__second) = __second.#ident {
773 let (__first_name, __first_value) = if let Some(__first) =
774 ::std::mem::take(&mut __first.#ident) {
775 (Some(__first.name), Some(__first.value))
776 } else {(None, None)};
777 let __name = __first_name.unwrap_or(__second.name);
778 let __second_value = __second.value;
779 #join.map(|__v| ::attribute_derive::parsing::Named{name: __name, value: __v});
780 }
781
782 }
783 }
784 }
785}
786
787fn parse_comma() -> TokenStream {
788 quote! {
789 if __input.is_empty() {
790 return Ok(__partial);
791 } else {
792 <::attribute_derive::__private::syn::Token![,] as
793 ::attribute_derive::__private::syn::parse::Parse>::parse(__input)?;
794 }
795 }
796}
797
798fn partial_attribute(
799 partial: &Ident,
800 vis: &Visibility,
801 fields: &[AttrField],
802 generics: &Generics,
803) -> Result {
804 let Some(first_field) = fields.first() else {
805 return Ok(quote!(#[derive(Default)] struct #partial #generics {}));
806 };
807 let fields = fields.iter().map(AttrField::partial);
808 let fields = if matches!(first_field.ident, IdentOrIdx::Ident(_)) {
809 quote!({#(#fields),*})
810 } else {
811 quote!((#(#fields),*);)
812 };
813 Ok(quote! {
814 #[derive(Default)]
815 #vis struct #partial #generics #fields
816 })
817}
818
819#[manyhow(impl_fn)]
820#[deprecated = "use `FromAttr` instead"]
821#[proc_macro_derive(Attribute, attributes(attribute, attr, from_attr))]
822pub fn attribute_derive(input: DeriveInput) -> Result {
823 from_attr_derive_impl(input)
824}
825
826#[manyhow(impl_fn)]
827#[proc_macro_derive(FromAttr, attributes(attribute, attr, from_attr))]
828pub fn from_attr_derive(
829 DeriveInput {
830 attrs,
831 vis,
832 ident,
833 generics,
834 data,
835 ..
836 }: DeriveInput,
837) -> Result {
838 let partial_ident = &format_ident!("{ident}Partial");
839
840 let StructAttrs {
841 ident: attribute_ident,
842 mut aliases,
843 error: ref struct_error,
844 } = StructAttrs::from_attrs(&ident, attrs)?;
846
847 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
848
849 if let Some(ref attribute_ident) = attribute_ident {
850 aliases.insert(0, attribute_ident.to_string());
851 }
852
853 let attribute_ident_trait = (!aliases.is_empty())
854 .then(|| {
855 quote! {
856 # use attribute_derive::AttributeIdent;
857
858 impl #impl_generics AttributeIdent for #ident #ty_generics #where_clause {
859 const IDENTS: &'static [&'static str] = &[#(#aliases),*];
860 }
861 }
862 })
863 .unwrap_or_default();
864
865 let (fields, conflicts) = match data {
866 syn::Data::Struct(DataStruct {
867 fields: fields @ (Fields::Named(_) | Fields::Unnamed(_)),
868 ..
869 }) => AttrField::parse_fields(fields, struct_error, attribute_ident)?,
870 _ => bail!("only works on structs with fields"),
871 };
872
873 let conflicts = conflicts.to_tokens(struct_error)?;
874
875 let partial_struct = partial_attribute(partial_ident, &vis, &fields, &generics)?;
876
877 let error_invalid_name = struct_error.unknown_field_error(&fields)?;
878
879 let partial_fields = fields.iter().map(AttrField::assign_partial);
880 let join_fields = fields.iter().map(AttrField::join_field);
881
882 let from_attr = if fields.len() == 1 && fields[0].positional {
883 let AttrField { ref ty, .. } = fields[0];
885 quote! {
886 # use ::attribute_derive::FromAttr;
887 # use ::attribute_derive::parsing::SpannedValue;
888 # use ::attribute_derive::__private::syn::parse::{ParseStream, Parse};
889 # use ::attribute_derive::__private::syn::{Result, Error};
890 impl #impl_generics FromAttr for #ident #ty_generics #where_clause {
891 fn parse_partial(input: ParseStream) -> Result<Self::Partial> {
892 <#ty as FromAttr>::parse_partial(input)
893 .map(SpannedValue::call_site)
894 .map(Some)
895 .map(#partial_ident)
896 }
897 }
898
899 }
900 } else {
901 let parse_positionals: Vec<_> = fields
902 .iter()
903 .filter_map(AttrField::parse_positional)
904 .collect();
905 let parse_named: Vec<_> = fields.iter().filter_map(AttrField::parse_named).collect();
906 quote! {
907 # use ::attribute_derive::parsing::AttributeMeta;
908 # use ::attribute_derive::__private::syn::parse::{ParseStream, Parse};
909 # use ::attribute_derive::__private::syn::{Result, Error};
910 impl #impl_generics AttributeMeta for #ident #ty_generics #where_clause {
911 fn parse_inner(__input: ParseStream) -> Result<Self::Partial> {
912 let mut __partial = #partial_ident::default();
913 #(#parse_positionals)*
914 while !__input.is_empty() {
915 #(#parse_named)*
916 return Err(__input.error(#error_invalid_name));
917 }
918 Ok(__partial)
919 }
920 }
921 }
922 };
923 Ok(quote! {
924 # use ::attribute_derive::parsing::{AttributeBase, SpannedValue};
925 # use ::attribute_derive::from_partial::FromPartial;
926 # use ::attribute_derive::__private::syn::parse::{ParseStream, Parse};
927 # use ::attribute_derive::__private::syn::{Result, Error};
928 #[allow(clippy::field_reassign_with_default, remove_unnecessary_else)]
929 const _: () = {
930 #attribute_ident_trait
931 #partial_struct
932
933 impl #impl_generics AttributeBase for #ident #ty_generics #where_clause {
934 type Partial = #partial_ident #ty_generics;
935 }
936
937 #from_attr
938
939 impl #impl_generics Parse for #ident #ty_generics #where_clause {
940 fn parse(__input: ParseStream) -> Result<Self> {
941 <Self as ::attribute_derive::FromAttr>::parse_input(__input)
942 }
943 }
944
945 impl #impl_generics FromPartial<#partial_ident #ty_generics> for #ident #ty_generics
946 #where_clause {
947 fn from(__partial: #partial_ident #ty_generics) -> Result<Self> {
948 #conflicts
949 Ok(Self {
950 #(#partial_fields),*
951 })
952 }
953
954 fn from_option(__partial: Option<#partial_ident #ty_generics>, _: &str)
955 -> Result<Self> {
956 <Self as FromPartial<#partial_ident #ty_generics>>::from(
957 __partial.unwrap_or_default())
958 }
959
960 fn join(
961 __first: Option<SpannedValue<#partial_ident #ty_generics>>,
962 __second: SpannedValue<#partial_ident #ty_generics>,
963 _: &str)
964 -> Result<Option<SpannedValue<#partial_ident #ty_generics>>> {
965 let mut __first = __first.unwrap_or_default().value;
966 let __span = __second.span;
967 let __second = __second.value;
968 #(#join_fields;)*
969 Ok(Some(SpannedValue { span: __span, value: __first}))
970 }
971 }
972 };
973 })
974}