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        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                // Precision of `.0` hides the entries but surpresses error when not used in
637                // `help` string.
638                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            // TODO let map_error = self.map_error();
679            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        // duplicate,
845    } = 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        // newtype struct
884        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}