attribute_derive_macro/
lib.rs

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    /// `expected_fields`
129    unknown_field: FormatString,
130    /// `expected_field`
131    unknown_field_single: FormatString,
132    unknown_field_empty: FormatString,
133    /// `field`
134    duplicate_field: FormatString,
135    /// `field`
136    missing_field: FormatString,
137    /// `field`, `attribute`, `example`
138    field_help: FormatString,
139    /// `first`, `second`
140    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
159// enum DuplicateStrategy {
160//     AggregateOrError,
161//     Error,
162//     AggregateOrOverride,
163//     Override,
164// }
165
166struct StructAttrs {
167    ident: Option<Ident>,
168    aliases: Vec<String>,
169    error: StructError,
170    // duplicate: DuplicateStrategy,
171}
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        // let mut duplicate: DuplicateStrategy = DuplicateStrategy::AggregateOrError;
185        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                        // "duplicate" => {
305                        //     parser.next_eq()                                .ok_or_else(||
306                        // ErrorMessage::call_site(VALID_FORMAT))?;     let strategy
307                        // = parser.next_ident()                                .ok_or_else(||
308                        // ErrorMessage::call_site(VALID_FORMAT))?;     duplicate =
309                        // match strategy.to_string().as_str() {
310                        //         "AggregateOrError" => DuplicateStrategy::AggregateOrError,
311                        //         "Error" => DuplicateStrategy::Error,
312                        //         "AggregateOrOverride" => DuplicateStrategy::AggregateOrOverride,
313                        //         "Override" => DuplicateStrategy::Override,
314                        //         _ => abort!(strategy, VALID_FORMAT),
315                        //     }
316                        // }
317                        _ => 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            // duplicate,
347        })
348    }
349}
350
351struct FieldAttrs {
352    optional: bool,
353    default: Option<TokenStream>,
354    // aggregate: bool,
355    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 aggregate: bool = true;
367        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                        // panic!("{:?}", parser.next_string());
405                        example = Some(
406                            parser
407                                .next_string()
408                                .ok_or_else(|| error_message!(parser.next(), "{VALID_FORMAT}"))?,
409                        );
410                    }
411                    // "aggregate" => {
412                    //     parser.next_eq()                                .ok_or_else(||
413                    // error_message!(parser.next(), "{VALID_FORMAT}"))?;     aggregate &=
414                    // parser.next_bool()                                .ok_or_else(||
415                    // error_message!(parser.next(), "{VALID_FORMAT}"))?; }
416                    "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            // aggregate,
443            conflicts,
444            example,
445            positional,
446        })
447    }
448}
449// TODO generally should use fully qualified names for trait function calls
450
451#[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        // The order must be deterministic to be friendly to tools like sccache
466        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                // Precision of `.0` hides the entries but surpresses error when not used in
642                // `help` string.
643                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            // TODO let map_error = self.map_error();
684            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        // duplicate,
850    } = 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        // newtype struct
889        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}