Skip to main content

object_rainbow_derive/
lib.rs

1//! `#[derive(...)]`s for [`object-rainbow`](<https://docs.rs/object-rainbow>).
2
3use std::collections::BTreeSet;
4
5use darling::{FromMeta, util::SpannedValue};
6use proc_macro::TokenStream;
7use quote::{ToTokens, quote, quote_spanned};
8use syn::{
9    Attribute, Data, DeriveInput, Error, Expr, FnArg, GenericParam, Generics, Ident, ImplItem,
10    ItemTrait, LitStr, TraitItem, Type, WherePredicate, parse::Parse, parse_macro_input,
11    parse_quote, parse_quote_spanned, spanned::Spanned, token::Comma,
12};
13
14use self::contains_generics::{GContext, type_contains_generics};
15
16mod contains_generics;
17
18fn bounds_g(generics: &Generics) -> BTreeSet<Ident> {
19    generics
20        .params
21        .iter()
22        .filter_map(|param| match param {
23            GenericParam::Lifetime(_) => None,
24            GenericParam::Type(param) => Some(&param.ident),
25            GenericParam::Const(param) => Some(&param.ident),
26        })
27        .cloned()
28        .collect()
29}
30
31#[derive(Debug, FromMeta)]
32#[darling(derive_syn_parse)]
33struct RainbowArgs {
34    #[darling(default)]
35    remote: Option<Type>,
36    #[darling(default)]
37    untagged: SpannedValue<bool>,
38}
39
40fn parse_for(name: &Ident, attrs: &[Attribute]) -> proc_macro2::TokenStream {
41    for attr in attrs {
42        if attr_str(attr).as_deref() == Some("rainbow") {
43            match attr.parse_args::<RainbowArgs>() {
44                Ok(RainbowArgs { remote, .. }) => {
45                    if let Some(remote) = remote {
46                        return remote.to_token_stream();
47                    }
48                }
49                Err(e) => return e.into_compile_error(),
50            }
51        }
52    }
53    name.to_token_stream()
54}
55
56fn parse_untagged(attrs: &[Attribute]) -> syn::Result<Option<SpannedValue<bool>>> {
57    let mut u = None;
58    for attr in attrs {
59        if attr_str(attr).as_deref() == Some("rainbow") {
60            let RainbowArgs { untagged, .. } = attr.parse_args()?;
61            if *untagged {
62                u = Some(untagged);
63            }
64        }
65    }
66    Ok(u)
67}
68
69/// ```rust
70/// use object_rainbow::{InlineOutput, ToOutput};
71///
72/// #[derive(ToOutput)]
73/// struct Three<A, B, C> {
74///     a: A,
75///     b: B,
76///     c: C,
77/// }
78///
79/// object_rainbow::assert_impl!(
80///     impl<A, B, C> ToOutput for Three<A, B, C>
81///     where
82///         A: InlineOutput,
83///         B: InlineOutput,
84///         C: ToOutput,
85///     {}
86/// );
87/// ```
88#[proc_macro_derive(ToOutput, attributes(rainbow))]
89pub fn derive_to_output(input: TokenStream) -> TokenStream {
90    let input = parse_macro_input!(input as DeriveInput);
91    let name = input.ident;
92    let generics = match bounds_to_output(input.generics, &input.data) {
93        Ok(g) => g,
94        Err(e) => return e.into_compile_error().into(),
95    };
96    let to_output = gen_to_output(&input.data, &input.attrs);
97    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
98    let target = parse_for(&name, &input.attrs);
99    let output = quote! {
100        #[automatically_derived]
101        impl #impl_generics ::object_rainbow::ToOutput for #target #ty_generics #where_clause {
102            fn to_output(&self, output: &mut impl ::object_rainbow::Output) {
103                #to_output
104            }
105        }
106    };
107    TokenStream::from(output)
108}
109
110fn bounds_to_output(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
111    let g = &bounds_g(&generics);
112    match data {
113        Data::Struct(data) => {
114            let last_at = data.fields.len().saturating_sub(1);
115            for (i, f) in data.fields.iter().enumerate() {
116                let last = i == last_at;
117                let ty = &f.ty;
118                let tr = if last {
119                    quote!(::object_rainbow::ToOutput)
120                } else {
121                    quote!(::object_rainbow::InlineOutput)
122                };
123                if !last || type_contains_generics(GContext { g, always: false }, ty) {
124                    generics.make_where_clause().predicates.push(
125                        parse_quote_spanned! { ty.span() =>
126                            #ty: #tr
127                        },
128                    );
129                }
130            }
131        }
132        Data::Enum(data) => {
133            for v in data.variants.iter() {
134                let last_at = v.fields.len().saturating_sub(1);
135                for (i, f) in v.fields.iter().enumerate() {
136                    let last = i == last_at;
137                    let ty = &f.ty;
138                    let tr = if last {
139                        quote!(::object_rainbow::ToOutput)
140                    } else {
141                        quote!(::object_rainbow::InlineOutput)
142                    };
143                    if !last || type_contains_generics(GContext { g, always: false }, ty) {
144                        generics.make_where_clause().predicates.push(
145                            parse_quote_spanned! { ty.span() =>
146                                #ty: #tr
147                            },
148                        );
149                    }
150                }
151            }
152        }
153        Data::Union(data) => {
154            return Err(Error::new_spanned(
155                data.union_token,
156                "`union`s are not supported",
157            ));
158        }
159    }
160    Ok(generics)
161}
162
163fn fields_to_output(fields: &syn::Fields) -> proc_macro2::TokenStream {
164    match fields {
165        syn::Fields::Named(fields) => {
166            let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
167            let to_output = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
168                quote_spanned! { f.ty.span() =>
169                    #i.to_output(output)
170                }
171            });
172            quote! {
173                { #(#let_self),* } => {
174                    #(#to_output);*
175                }
176            }
177        }
178        syn::Fields::Unnamed(fields) => {
179            let let_self = fields
180                .unnamed
181                .iter()
182                .enumerate()
183                .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
184            let to_output = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
185                quote_spanned! { f.ty.span() =>
186                    #i.to_output(output)
187                }
188            });
189            quote! {
190                (#(#let_self),*) => {
191                    #(#to_output);*
192                }
193            }
194        }
195        syn::Fields::Unit => quote! {
196            => {}
197        },
198    }
199}
200
201fn gen_to_output(data: &Data, attrs: &[Attribute]) -> proc_macro2::TokenStream {
202    let untagged = match parse_untagged(attrs) {
203        Ok(untagged) => untagged,
204        Err(e) => return e.into_compile_error(),
205    };
206    match data {
207        Data::Struct(data) => {
208            let arm = fields_to_output(&data.fields);
209            quote! {
210                match self {
211                    Self #arm
212                }
213            }
214        }
215        Data::Enum(data) => {
216            if data.variants.is_empty() {
217                return quote! {};
218            }
219            let to_output = data.variants.iter().map(|v| {
220                let ident = &v.ident;
221                let arm = fields_to_output(&v.fields);
222                quote! { Self::#ident #arm }
223            });
224            let tagged = if untagged.is_none() {
225                quote! {
226                    let kind = ::object_rainbow::Enum::kind(self);
227                    let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
228                    tag.to_output(output);
229                }
230            } else {
231                quote! {}
232            };
233            quote! {
234                #tagged
235                match self {
236                    #(#to_output)*
237                }
238            }
239        }
240        Data::Union(data) => {
241            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
242        }
243    }
244}
245
246/// ```rust
247/// use object_rainbow::{InlineOutput, ToOutput};
248///
249/// #[derive(ToOutput, InlineOutput)]
250/// struct Three<A, B, C> {
251///     a: A,
252///     b: B,
253///     c: C,
254/// }
255///
256/// object_rainbow::assert_impl!(
257///     impl<A, B, C> InlineOutput for Three<A, B, C>
258///     where
259///         A: InlineOutput,
260///         B: InlineOutput,
261///         C: InlineOutput,
262///     {}
263/// );
264/// ```
265#[proc_macro_derive(InlineOutput)]
266pub fn derive_inline_output(input: TokenStream) -> TokenStream {
267    let input = parse_macro_input!(input as DeriveInput);
268    let name = input.ident;
269    let generics = match bounds_inline_output(input.generics, &input.data) {
270        Ok(g) => g,
271        Err(e) => return e.into_compile_error().into(),
272    };
273    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
274    let target = parse_for(&name, &input.attrs);
275    let output = quote! {
276        #[automatically_derived]
277        impl #impl_generics ::object_rainbow::InlineOutput for #target #ty_generics #where_clause {}
278    };
279    TokenStream::from(output)
280}
281
282fn bounds_inline_output(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
283    match data {
284        Data::Struct(data) => {
285            for f in data.fields.iter() {
286                let ty = &f.ty;
287                generics
288                    .make_where_clause()
289                    .predicates
290                    .push(parse_quote_spanned! { ty.span() =>
291                        #ty: ::object_rainbow::InlineOutput
292                    });
293            }
294        }
295        Data::Enum(data) => {
296            for v in data.variants.iter() {
297                for f in v.fields.iter() {
298                    let ty = &f.ty;
299                    generics.make_where_clause().predicates.push(
300                        parse_quote_spanned! { ty.span() =>
301                            #ty: ::object_rainbow::InlineOutput
302                        },
303                    );
304                }
305            }
306        }
307        Data::Union(data) => {
308            return Err(Error::new_spanned(
309                data.union_token,
310                "`union`s are not supported",
311            ));
312        }
313    }
314    Ok(generics)
315}
316
317/// ```rust
318/// use object_rainbow::ListHashes;
319///
320/// #[derive(ListHashes)]
321/// struct Three<A, B, C> {
322///     a: A,
323///     b: B,
324///     c: C,
325/// }
326///
327/// object_rainbow::assert_impl!(
328///     impl<A, B, C> ListHashes for Three<A, B, C>
329///     where
330///         A: ListHashes,
331///         B: ListHashes,
332///         C: ListHashes,
333///     {}
334/// );
335/// ```
336#[proc_macro_derive(ListHashes, attributes(topology, rainbow))]
337pub fn derive_list_hashes(input: TokenStream) -> TokenStream {
338    let input = parse_macro_input!(input as DeriveInput);
339    let name = input.ident;
340    let generics = input.generics.clone();
341    let (_, ty_generics, _) = generics.split_for_impl();
342    let generics = match bounds_list_hashes(input.generics, &input.data) {
343        Ok(g) => g,
344        Err(e) => return e.into_compile_error().into(),
345    };
346    let list_hashes = gen_list_hashes(&input.data, &input.attrs);
347    let (impl_generics, _, where_clause) = generics.split_for_impl();
348    let target = parse_for(&name, &input.attrs);
349    let output = quote! {
350        #[automatically_derived]
351        impl #impl_generics ::object_rainbow::ListHashes for #target #ty_generics #where_clause {
352            fn list_hashes(&self, visitor: &mut impl FnMut(::object_rainbow::Hash)) {
353                #list_hashes
354            }
355        }
356    };
357    TokenStream::from(output)
358}
359
360fn bounds_list_hashes(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
361    let g = &bounds_g(&generics);
362    match data {
363        Data::Struct(data) => {
364            for f in data.fields.iter() {
365                let ty = &f.ty;
366                if type_contains_generics(GContext { g, always: false }, ty) {
367                    generics.make_where_clause().predicates.push(
368                        parse_quote_spanned! { ty.span() =>
369                            #ty: ::object_rainbow::ListHashes
370                        },
371                    );
372                }
373            }
374        }
375        Data::Enum(data) => {
376            for v in data.variants.iter() {
377                for f in v.fields.iter() {
378                    let ty = &f.ty;
379                    if type_contains_generics(GContext { g, always: false }, ty) {
380                        generics.make_where_clause().predicates.push(
381                            parse_quote_spanned! { ty.span() =>
382                                #ty: ::object_rainbow::ListHashes
383                            },
384                        );
385                    }
386                }
387            }
388        }
389        Data::Union(data) => {
390            return Err(Error::new_spanned(
391                data.union_token,
392                "`union`s are not supported",
393            ));
394        }
395    }
396    Ok(generics)
397}
398
399fn fields_list_hashes(fields: &syn::Fields) -> proc_macro2::TokenStream {
400    match fields {
401        syn::Fields::Named(fields) => {
402            let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
403            let list_hashes = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
404                quote_spanned! { f.ty.span() =>
405                    #i.list_hashes(visitor)
406                }
407            });
408            quote! {
409                { #(#let_self),* } => {
410                    #(#list_hashes);*
411                }
412            }
413        }
414        syn::Fields::Unnamed(fields) => {
415            let let_self = fields
416                .unnamed
417                .iter()
418                .enumerate()
419                .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
420            let list_hashes = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
421                quote_spanned! { f.ty.span() =>
422                    #i.list_hashes(visitor)
423                }
424            });
425            quote! {
426                (#(#let_self),*) => {
427                    #(#list_hashes);*
428                }
429            }
430        }
431        syn::Fields::Unit => quote! {
432            => {}
433        },
434    }
435}
436
437fn gen_list_hashes(data: &Data, attrs: &[Attribute]) -> proc_macro2::TokenStream {
438    let untagged = match parse_untagged(attrs) {
439        Ok(untagged) => untagged,
440        Err(e) => return e.into_compile_error(),
441    };
442    match data {
443        Data::Struct(data) => {
444            let arm = fields_list_hashes(&data.fields);
445            quote! {
446                match self {
447                    Self #arm
448                }
449            }
450        }
451        Data::Enum(data) => {
452            if data.variants.is_empty() {
453                return quote! {};
454            }
455            let to_output = data.variants.iter().map(|v| {
456                let ident = &v.ident;
457                let arm = fields_list_hashes(&v.fields);
458                quote! { Self::#ident #arm }
459            });
460            let tagged = if untagged.is_none() {
461                quote! {
462                    let kind = ::object_rainbow::Enum::kind(self);
463                    let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
464                    tag.list_hashes(visitor);
465                }
466            } else {
467                quote! {}
468            };
469            quote! {
470                #tagged;
471                match self {
472                    #(#to_output)*
473                }
474            }
475        }
476        Data::Union(data) => {
477            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
478        }
479    }
480}
481
482/// ```rust
483/// use object_rainbow::{ListHashes, Topological};
484///
485/// #[derive(ListHashes, Topological)]
486/// struct Three<A, B, C> {
487///     a: A,
488///     b: B,
489///     c: C,
490/// }
491///
492/// object_rainbow::assert_impl!(
493///     impl<A, B, C> Topological for Three<A, B, C>
494///     where
495///         A: Topological,
496///         B: Topological,
497///         C: Topological,
498///     {}
499/// );
500/// ```
501#[proc_macro_derive(Topological, attributes(topology))]
502pub fn derive_topological(input: TokenStream) -> TokenStream {
503    let input = parse_macro_input!(input as DeriveInput);
504    let name = input.ident;
505    let generics = input.generics.clone();
506    let (_, ty_generics, _) = generics.split_for_impl();
507    let generics = match bounds_topological(input.generics, &input.data, &input.attrs, &name) {
508        Ok(g) => g,
509        Err(e) => return e.into_compile_error().into(),
510    };
511    let traverse = gen_traverse(&input.data, &input.attrs);
512    let (impl_generics, _, where_clause) = generics.split_for_impl();
513    let target = parse_for(&name, &input.attrs);
514    let output = quote! {
515        const _: () = {
516            #[automatically_derived]
517            impl #impl_generics ::object_rainbow::Topological for #target #ty_generics
518            #where_clause
519            {
520                fn traverse(&self, visitor: &mut impl ::object_rainbow::PointVisitor) {
521                    #traverse
522                }
523            }
524        };
525    };
526    TokenStream::from(output)
527}
528
529#[derive(Debug, FromMeta)]
530#[darling(derive_syn_parse)]
531struct ContainerTopologyArgs {
532    #[darling(default)]
533    recursive: bool,
534    #[darling(default)]
535    inline: bool,
536    #[darling(default)]
537    unchecked: bool,
538    #[darling(default)]
539    bound: Option<LitStr>,
540}
541
542fn parse_recursive_inline(
543    attrs: &[Attribute],
544) -> syn::Result<(bool, bool, bool, Vec<WherePredicate>)> {
545    let mut r = false;
546    let mut i = false;
547    let mut u = false;
548    let mut wheres = Vec::new();
549    for attr in attrs {
550        if attr_str(attr).as_deref() == Some("topology") {
551            let ContainerTopologyArgs {
552                recursive,
553                inline,
554                unchecked,
555                bound,
556            } = attr.parse_args()?;
557            if recursive {
558                r = true;
559            }
560            if inline {
561                i = true;
562            }
563            if unchecked {
564                u = true;
565            }
566            if let Some(bound) = bound {
567                wheres.push(bound.parse()?);
568            }
569        }
570    }
571    Ok((r, i, u, wheres))
572}
573
574#[derive(Debug, FromMeta)]
575#[darling(derive_syn_parse)]
576struct FieldTopologyArgs {
577    #[darling(default)]
578    unchecked: bool,
579    with: Option<Expr>,
580}
581
582fn bounds_topological(
583    mut generics: Generics,
584    data: &Data,
585    attrs: &[Attribute],
586    name: &Ident,
587) -> syn::Result<Generics> {
588    let (recursive, inline, u, wheres) = parse_recursive_inline(attrs)?;
589    let g = &bounds_g(&generics);
590    let bound = if recursive {
591        quote! { ::object_rainbow::Traversible }
592    } else {
593        quote! { ::object_rainbow::Topological }
594    };
595    match data {
596        Data::Struct(data) => {
597            'field: for f in data.fields.iter() {
598                let ty = &f.ty;
599                for attr in &f.attrs {
600                    if attr_str(attr).as_deref() == Some("topology") {
601                        let FieldTopologyArgs { unchecked, .. } = attr.parse_args()?;
602                        if unchecked {
603                            continue 'field;
604                        }
605                    }
606                }
607                if u {
608                    continue 'field;
609                }
610                if type_contains_generics(GContext { g, always: false }, ty) {
611                    generics.make_where_clause().predicates.push(
612                        parse_quote_spanned! { ty.span() =>
613                            #ty: #bound
614                        },
615                    );
616                }
617            }
618        }
619        Data::Enum(data) => {
620            for v in data.variants.iter() {
621                'field: for f in v.fields.iter() {
622                    let ty = &f.ty;
623                    for attr in &f.attrs {
624                        if attr_str(attr).as_deref() == Some("topology") {
625                            let FieldTopologyArgs { unchecked, .. } = attr.parse_args()?;
626                            if unchecked {
627                                continue 'field;
628                            }
629                        }
630                    }
631                    if u {
632                        continue 'field;
633                    }
634                    if type_contains_generics(GContext { g, always: false }, ty) {
635                        generics.make_where_clause().predicates.push(
636                            parse_quote_spanned! { ty.span() =>
637                                #ty: #bound
638                            },
639                        );
640                    }
641                }
642            }
643        }
644        Data::Union(data) => {
645            return Err(Error::new_spanned(
646                data.union_token,
647                "`union`s are not supported",
648            ));
649        }
650    }
651    let output_bound = if inline {
652        quote! {
653            ::object_rainbow::InlineOutput
654        }
655    } else {
656        quote! {
657            ::object_rainbow::ToOutput
658        }
659    };
660    if recursive {
661        generics
662            .make_where_clause()
663            .predicates
664            .push(parse_quote_spanned! { name.span() =>
665                Self: #output_bound + ::object_rainbow::Tagged
666            });
667    }
668    for bound in wheres {
669        generics.make_where_clause().predicates.push(bound);
670    }
671    Ok(generics)
672}
673
674fn fields_traverse(fields: &syn::Fields) -> proc_macro2::TokenStream {
675    match fields {
676        syn::Fields::Named(fields) => {
677            let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
678            let traverse = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
679                let mut w = None;
680                for attr in &f.attrs {
681                    if attr_str(attr).as_deref() == Some("topology") {
682                        let FieldTopologyArgs { with, .. } = match attr.parse_args() {
683                            Ok(args) => args,
684                            Err(e) => return e.into_compile_error(),
685                        };
686                        if let Some(with) = with {
687                            w = Some(with);
688                        }
689                    }
690                }
691                if let Some(with) = w {
692                    quote_spanned! { f.ty.span() =>
693                        #with(#i, visitor)
694                    }
695                } else {
696                    quote_spanned! { f.ty.span() =>
697                        #i.traverse(visitor)
698                    }
699                }
700            });
701            quote! {
702                { #(#let_self),* } => {
703                    #(#traverse);*
704                }
705            }
706        }
707        syn::Fields::Unnamed(fields) => {
708            let let_self = fields
709                .unnamed
710                .iter()
711                .enumerate()
712                .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
713            let traverse = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
714                let mut w = None;
715                for attr in &f.attrs {
716                    if attr_str(attr).as_deref() == Some("topology") {
717                        let FieldTopologyArgs { with, .. } = match attr.parse_args() {
718                            Ok(args) => args,
719                            Err(e) => return e.into_compile_error(),
720                        };
721                        if let Some(with) = with {
722                            w = Some(with);
723                        }
724                    }
725                }
726                if let Some(with) = w {
727                    quote_spanned! { f.ty.span() =>
728                        #with(#i, visitor)
729                    }
730                } else {
731                    quote_spanned! { f.ty.span() =>
732                        #i.traverse(visitor)
733                    }
734                }
735            });
736            quote! {
737                (#(#let_self),*) => {
738                    #(#traverse);*
739                }
740            }
741        }
742        syn::Fields::Unit => quote! {
743            => {}
744        },
745    }
746}
747
748fn gen_traverse(data: &Data, attrs: &[Attribute]) -> proc_macro2::TokenStream {
749    let untagged = match parse_untagged(attrs) {
750        Ok(untagged) => untagged,
751        Err(e) => return e.into_compile_error(),
752    };
753    match data {
754        Data::Struct(data) => {
755            let arm = fields_traverse(&data.fields);
756            quote! {
757                match self {
758                    Self #arm
759                }
760            }
761        }
762        Data::Enum(data) => {
763            if data.variants.is_empty() {
764                return quote! {};
765            }
766            let to_output = data.variants.iter().map(|v| {
767                let ident = &v.ident;
768                let arm = fields_traverse(&v.fields);
769                quote! { Self::#ident #arm }
770            });
771            let tagged = if untagged.is_none() {
772                quote! {
773                    let kind = ::object_rainbow::Enum::kind(self);
774                    let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
775                    tag.traverse(visitor);
776                }
777            } else {
778                quote! {}
779            };
780            quote! {
781                #tagged;
782                match self {
783                    #(#to_output)*
784                }
785            }
786        }
787        Data::Union(data) => {
788            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
789        }
790    }
791}
792
793/// ```rust
794/// use object_rainbow::Tagged;
795///
796/// #[derive(Tagged)]
797/// struct Three<A, B, C> {
798///     a: A,
799///     #[tags(skip)]
800///     b: B,
801///     c: C,
802/// }
803///
804/// object_rainbow::assert_impl!(
805///     impl<A, B, C> Tagged for Three<A, B, C>
806///     where
807///         A: Tagged,
808///         C: Tagged,
809///     {}
810/// );
811/// ```
812#[proc_macro_derive(Tagged, attributes(tags))]
813pub fn derive_tagged(input: TokenStream) -> TokenStream {
814    let input = parse_macro_input!(input as DeriveInput);
815    let name = input.ident;
816    let mut errors = Vec::new();
817    let generics = match bounds_tagged(input.generics, &input.data, &mut errors) {
818        Ok(g) => g,
819        Err(e) => return e.into_compile_error().into(),
820    };
821    let tags = gen_tags(&input.data, &input.attrs, &mut errors);
822    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
823    let errors = errors.into_iter().map(|e| e.into_compile_error());
824    let target = parse_for(&name, &input.attrs);
825    let output = quote! {
826        #(#errors)*
827
828        #[automatically_derived]
829        impl #impl_generics ::object_rainbow::Tagged for #target #ty_generics #where_clause {
830            const TAGS: ::object_rainbow::Tags = #tags;
831        }
832    };
833    TokenStream::from(output)
834}
835
836struct FieldTagArgs {
837    skip: bool,
838}
839
840impl Parse for FieldTagArgs {
841    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
842        let mut skip = false;
843        while !input.is_empty() {
844            let ident = input.parse::<Ident>()?;
845            if ident.to_string().as_str() != "skip" {
846                return Err(Error::new(ident.span(), "expected: skip"));
847            }
848            skip = true;
849            if !input.is_empty() {
850                input.parse::<Comma>()?;
851            }
852        }
853        Ok(Self { skip })
854    }
855}
856
857fn bounds_tagged(
858    mut generics: Generics,
859    data: &Data,
860    errors: &mut Vec<Error>,
861) -> syn::Result<Generics> {
862    let g = &bounds_g(&generics);
863    match data {
864        Data::Struct(data) => {
865            for f in data.fields.iter() {
866                let mut skip = false;
867                for attr in &f.attrs {
868                    if attr_str(attr).as_deref() == Some("tags") {
869                        match attr.parse_args::<FieldTagArgs>() {
870                            Ok(args) => skip |= args.skip,
871                            Err(e) => errors.push(e),
872                        }
873                    }
874                }
875                if !skip {
876                    let ty = &f.ty;
877                    if type_contains_generics(GContext { g, always: false }, ty) {
878                        generics.make_where_clause().predicates.push(
879                            parse_quote_spanned! { ty.span() =>
880                                #ty: ::object_rainbow::Tagged
881                            },
882                        );
883                    }
884                }
885            }
886        }
887        Data::Enum(data) => {
888            for v in data.variants.iter() {
889                for f in v.fields.iter() {
890                    let mut skip = false;
891                    for attr in &f.attrs {
892                        if attr_str(attr).as_deref() == Some("tags") {
893                            match attr.parse_args::<FieldTagArgs>() {
894                                Ok(args) => skip |= args.skip,
895                                Err(e) => errors.push(e),
896                            }
897                        }
898                    }
899                    if !skip {
900                        let ty = &f.ty;
901                        if type_contains_generics(GContext { g, always: false }, ty) {
902                            generics.make_where_clause().predicates.push(
903                                parse_quote_spanned! { ty.span() =>
904                                    #ty: ::object_rainbow::Tagged
905                                },
906                            );
907                        }
908                    }
909                }
910            }
911        }
912        Data::Union(data) => {
913            return Err(Error::new_spanned(
914                data.union_token,
915                "`union`s are not supported",
916            ));
917        }
918    }
919    Ok(generics)
920}
921
922struct StructTagArgs {
923    tags: Vec<LitStr>,
924}
925
926impl Parse for StructTagArgs {
927    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
928        let mut tags = Vec::new();
929        while !input.is_empty() {
930            let tag = input.parse::<LitStr>()?;
931            tags.push(tag);
932            if !input.is_empty() {
933                input.parse::<Comma>()?;
934            }
935        }
936        Ok(Self { tags })
937    }
938}
939
940fn fields_tags(fields: &syn::Fields) -> Vec<proc_macro2::TokenStream> {
941    fields
942        .iter()
943        .filter_map(|f| {
944            let mut skip = false;
945            for attr in &f.attrs {
946                if attr_str(attr).as_deref() == Some("tags") {
947                    skip |= attr.parse_args::<FieldTagArgs>().ok()?.skip;
948                }
949            }
950            let ty = &f.ty;
951            (!skip).then_some(quote! { <#ty as ::object_rainbow::Tagged>::TAGS })
952        })
953        .collect()
954}
955
956fn gen_tags(data: &Data, attrs: &[Attribute], errors: &mut Vec<Error>) -> proc_macro2::TokenStream {
957    let untagged = match parse_untagged(attrs) {
958        Ok(untagged) => untagged,
959        Err(e) => return e.into_compile_error(),
960    };
961    match data {
962        Data::Struct(data) => {
963            let mut tags = Vec::new();
964            for attr in attrs {
965                if attr_str(attr).as_deref() == Some("tags") {
966                    match attr.parse_args::<StructTagArgs>() {
967                        Ok(mut args) => tags.append(&mut args.tags),
968                        Err(e) => errors.push(e),
969                    }
970                }
971            }
972            let nested = fields_tags(&data.fields);
973            if nested.len() == 1 && tags.is_empty() {
974                let nested = nested.into_iter().next().unwrap();
975                quote! {
976                    #nested
977                }
978            } else {
979                quote! {
980                    ::object_rainbow::Tags(&[#(#tags),*], &[#(&#nested),*])
981                }
982            }
983        }
984        Data::Enum(data) => {
985            let mut tags = Vec::new();
986            for attr in attrs {
987                if attr_str(attr).as_deref() == Some("tags") {
988                    match attr.parse_args::<StructTagArgs>() {
989                        Ok(mut args) => tags.append(&mut args.tags),
990                        Err(e) => errors.push(e),
991                    }
992                }
993            }
994            let mut nested: Vec<_> = data
995                .variants
996                .iter()
997                .flat_map(|v| fields_tags(&v.fields))
998                .collect();
999            let kind_tags = quote! {
1000                <
1001                    <
1002                        <
1003                            Self
1004                            as
1005                            ::object_rainbow::Enum
1006                        >::Kind
1007                        as
1008                        ::object_rainbow::enumkind::EnumKind
1009                    >::Tag
1010                    as  ::object_rainbow::Tagged
1011                >::TAGS
1012            };
1013            if untagged.is_none() {
1014                nested.insert(0, kind_tags);
1015            }
1016            if nested.len() == 1 && tags.is_empty() {
1017                let nested = nested.into_iter().next().unwrap();
1018                quote! {
1019                    #nested
1020                }
1021            } else {
1022                quote! {
1023                    ::object_rainbow::Tags(&[#(#tags),*], &[#(&#nested),*])
1024                }
1025            }
1026        }
1027        Data::Union(data) => {
1028            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1029        }
1030    }
1031}
1032
1033/// ```rust
1034/// use object_rainbow::Size;
1035///
1036/// #[derive(Size)]
1037/// struct Three<A, B, C> {
1038///     a: A,
1039///     b: B,
1040///     c: C,
1041/// }
1042///
1043/// object_rainbow::assert_impl!(
1044///     impl<A, B, C> Size for Three<A, B, C>
1045///     where
1046///         A: Size<Size = typenum::U2>,
1047///         B: Size<Size = typenum::U3>,
1048///         C: Size<Size = typenum::U7>,
1049///     {}
1050/// );
1051///
1052/// assert_eq!(Three::<[u8; 2], [u8; 3], [u8; 7]>::SIZE, 12);
1053/// ```
1054#[proc_macro_derive(Size)]
1055pub fn derive_size(input: TokenStream) -> TokenStream {
1056    let input = parse_macro_input!(input as DeriveInput);
1057    let name = input.ident;
1058    let size_arr = gen_size_arr(&input.data);
1059    let size = gen_size(&input.data);
1060    let (generics, is_enum) = match bounds_size(input.generics.clone(), &input.data, &size_arr) {
1061        Ok(g) => g,
1062        Err(e) => return e.into_compile_error().into(),
1063    };
1064    let (_, ty_generics, where_clause) = generics.split_for_impl();
1065    let mut generics = input.generics;
1066    if is_enum {
1067        generics.params.push(parse_quote!(
1068            __Output: ::object_rainbow::typenum::Unsigned
1069        ));
1070    }
1071    let (impl_generics, _, _) = generics.split_for_impl();
1072    let target = parse_for(&name, &input.attrs);
1073    let output = quote! {
1074        const _: () = {
1075            use ::object_rainbow::typenum::tarr;
1076
1077            #[automatically_derived]
1078            impl #impl_generics ::object_rainbow::Size for #target #ty_generics #where_clause {
1079                const SIZE: usize = #size;
1080
1081                type Size = <#size_arr as ::object_rainbow::typenum::FoldAdd>::Output;
1082            }
1083        };
1084    };
1085    TokenStream::from(output)
1086}
1087
1088fn bounds_size(
1089    mut generics: Generics,
1090    data: &Data,
1091    size_arr: &proc_macro2::TokenStream,
1092) -> syn::Result<(Generics, bool)> {
1093    let g = &bounds_g(&generics);
1094    let is_enum = match data {
1095        Data::Struct(data) => {
1096            for f in data.fields.iter() {
1097                let ty = &f.ty;
1098                if type_contains_generics(GContext { g, always: false }, ty) {
1099                    generics.make_where_clause().predicates.push(
1100                        parse_quote_spanned! { ty.span() =>
1101                            #ty: ::object_rainbow::Size
1102                        },
1103                    );
1104                }
1105            }
1106            generics.make_where_clause().predicates.push(parse_quote!(
1107                #size_arr: ::object_rainbow::typenum::FoldAdd<
1108                    Output: ::object_rainbow::typenum::Unsigned
1109                >
1110            ));
1111            false
1112        }
1113        Data::Enum(data) => {
1114            for v in data.variants.iter() {
1115                for f in v.fields.iter() {
1116                    let ty = &f.ty;
1117                    if type_contains_generics(GContext { g, always: false }, ty) {
1118                        generics.make_where_clause().predicates.push(
1119                            parse_quote_spanned! { ty.span() =>
1120                                #ty: ::object_rainbow::Size
1121                            },
1122                        );
1123                    }
1124                }
1125            }
1126            for v in data.variants.iter().skip(1) {
1127                let arr = fields_size_arr(&v.fields, true);
1128                generics.make_where_clause().predicates.push(parse_quote!(
1129                    #arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
1130                ));
1131            }
1132            generics.make_where_clause().predicates.push(parse_quote!(
1133                #size_arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
1134            ));
1135            true
1136        }
1137        Data::Union(data) => {
1138            return Err(Error::new_spanned(
1139                data.union_token,
1140                "`union`s are not supported",
1141            ));
1142        }
1143    };
1144    Ok((generics, is_enum))
1145}
1146
1147fn fields_size_arr(fields: &syn::Fields, as_enum: bool) -> proc_macro2::TokenStream {
1148    let kind_size = quote! {
1149        <
1150            <
1151                <
1152                    Self
1153                    as
1154                    ::object_rainbow::Enum
1155                >::Kind
1156                as
1157                ::object_rainbow::enumkind::EnumKind
1158            >::Tag
1159            as  ::object_rainbow::Size
1160        >::Size
1161    };
1162    if fields.is_empty() {
1163        return if as_enum {
1164            quote! { tarr![#kind_size, ::object_rainbow::typenum::consts::U0] }
1165        } else {
1166            quote! { tarr![::object_rainbow::typenum::consts::U0] }
1167        };
1168    }
1169    let size_arr = fields.iter().map(|f| {
1170        let ty = &f.ty;
1171        quote! { <#ty as ::object_rainbow::Size>::Size }
1172    });
1173    if as_enum {
1174        quote! { tarr![#kind_size, ::object_rainbow::typenum::consts::U0, #(#size_arr),*] }
1175    } else {
1176        quote! { tarr![::object_rainbow::typenum::consts::U0, #(#size_arr),*] }
1177    }
1178}
1179
1180fn gen_size_arr(data: &Data) -> proc_macro2::TokenStream {
1181    match data {
1182        Data::Struct(data) => fields_size_arr(&data.fields, false),
1183        Data::Enum(data) => {
1184            if let Some(v) = data.variants.first() {
1185                fields_size_arr(&v.fields, true)
1186            } else {
1187                Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
1188                    .into_compile_error()
1189            }
1190        }
1191        Data::Union(data) => {
1192            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1193        }
1194    }
1195}
1196
1197fn fields_size(fields: &syn::Fields) -> proc_macro2::TokenStream {
1198    if fields.is_empty() {
1199        return quote! {0};
1200    }
1201    let size = fields.iter().map(|f| {
1202        let ty = &f.ty;
1203        quote! { <#ty as ::object_rainbow::Size>::SIZE }
1204    });
1205    quote! {
1206        #(#size)+*
1207    }
1208}
1209
1210fn gen_size(data: &Data) -> proc_macro2::TokenStream {
1211    match data {
1212        Data::Struct(data) => fields_size(&data.fields),
1213        Data::Enum(data) => {
1214            if let Some(v) = data.variants.first() {
1215                let size = fields_size(&v.fields);
1216                let kind_size = quote! {
1217                    <
1218                        <
1219                            <
1220                                Self
1221                                as
1222                                ::object_rainbow::Enum
1223                            >::Kind
1224                            as
1225                            ::object_rainbow::enumkind::EnumKind
1226                        >::Tag
1227                        as  ::object_rainbow::Size
1228                    >::SIZE
1229                };
1230                quote! { #kind_size + #size }
1231            } else {
1232                Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
1233                    .into_compile_error()
1234            }
1235        }
1236        Data::Union(data) => {
1237            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1238        }
1239    }
1240}
1241
1242/// ```rust
1243/// use object_rainbow::{Parse, ParseInline, ParseInput};
1244///
1245/// #[derive(Parse)]
1246/// struct Three<A, B, C> {
1247///     a: A,
1248///     b: B,
1249///     c: C,
1250/// }
1251///
1252/// object_rainbow::assert_impl!(
1253///     impl<A, B, C, I> Parse<I> for Three<A, B, C>
1254///     where
1255///         A: ParseInline<I>,
1256///         B: ParseInline<I>,
1257///         C: Parse<I>,
1258///         I: ParseInput,
1259///     {}
1260/// );
1261/// ```
1262#[proc_macro_derive(Parse, attributes(parse))]
1263pub fn derive_parse(input: TokenStream) -> TokenStream {
1264    let input = parse_macro_input!(input as DeriveInput);
1265    let name = input.ident;
1266    let generics = input.generics.clone();
1267    let (_, ty_generics, _) = generics.split_for_impl();
1268    let (inp, generics) = match bounds_parse(input.generics, &input.data, &input.attrs) {
1269        Ok(g) => g,
1270        Err(e) => return e.into_compile_error().into(),
1271    };
1272    let (parse, enum_parse) = gen_parse(&input.data, &input.attrs);
1273    let (impl_generics, _, where_clause) = generics.split_for_impl();
1274    let target = parse_for(&name, &input.attrs);
1275    let enum_parse = enum_parse.map(|enum_parse| {
1276        quote! {
1277            #[automatically_derived]
1278            impl #impl_generics ::object_rainbow::enumkind::EnumParse<#inp> for #target #ty_generics
1279            #where_clause
1280            {
1281                fn enum_parse(
1282                    kind: <Self as ::object_rainbow::Enum>::Kind, mut input: #inp,
1283                ) -> ::object_rainbow::Result<Self> {
1284                    #enum_parse
1285                }
1286            }
1287        }
1288    });
1289    let output = quote! {
1290        const _: () = {
1291            #[automatically_derived]
1292            impl #impl_generics ::object_rainbow::Parse<#inp> for #target #ty_generics
1293            #where_clause
1294            {
1295                fn parse(mut input: #inp) -> ::object_rainbow::Result<Self> {
1296                    #parse
1297                }
1298            }
1299
1300            #enum_parse
1301        };
1302    };
1303    TokenStream::from(output)
1304}
1305
1306#[derive(Debug, FromMeta)]
1307#[darling(derive_syn_parse)]
1308struct ContainerParseArgs {
1309    #[darling(default)]
1310    unchecked: bool,
1311    #[darling(default)]
1312    bound: Option<LitStr>,
1313    #[darling(default)]
1314    generic: Option<LitStr>,
1315    #[darling(default)]
1316    input: Option<LitStr>,
1317}
1318
1319fn parse_parse_args(
1320    attrs: &[Attribute],
1321) -> syn::Result<(bool, Ident, Vec<WherePredicate>, Vec<GenericParam>)> {
1322    let mut u = false;
1323    let mut inp = parse_quote!(__I);
1324    let mut wheres = Vec::new();
1325    let mut ig = Vec::new();
1326    for attr in attrs {
1327        if attr_str(attr).as_deref() == Some("parse") {
1328            let ContainerParseArgs {
1329                unchecked,
1330                input,
1331                bound,
1332                generic,
1333            } = attr.parse_args()?;
1334            if unchecked {
1335                u = true;
1336            }
1337            if let Some(input) = input {
1338                inp = input.parse()?;
1339            }
1340            if let Some(bound) = bound {
1341                wheres.push(bound.parse()?);
1342            }
1343            if let Some(generic) = generic {
1344                ig.push(generic.parse()?);
1345            }
1346        }
1347    }
1348    Ok((u, inp, wheres, ig))
1349}
1350
1351#[derive(Debug, FromMeta)]
1352#[darling(derive_syn_parse)]
1353struct ParseArgs {
1354    #[darling(default)]
1355    unchecked: bool,
1356    with: Option<Expr>,
1357}
1358
1359fn bounds_parse(
1360    mut generics: Generics,
1361    data: &Data,
1362    attrs: &[Attribute],
1363) -> syn::Result<(Ident, Generics)> {
1364    let (recursive, _, _, _) = parse_recursive_inline(attrs)?;
1365    let (u, inp, wheres, ig) = parse_parse_args(attrs)?;
1366    let tr = |last| match (last, recursive) {
1367        (true, true) => {
1368            quote!(::object_rainbow::Parse<#inp> + ::object_rainbow::Object<#inp::Extra>)
1369        }
1370        (true, false) => quote!(::object_rainbow::Parse<#inp>),
1371        (false, true) => {
1372            quote!(::object_rainbow::ParseInline<#inp> + ::object_rainbow::Inline<#inp::Extra>)
1373        }
1374        (false, false) => quote!(::object_rainbow::ParseInline<#inp>),
1375    };
1376    match data {
1377        Data::Struct(data) => {
1378            let last_at = data.fields.len().saturating_sub(1);
1379            'field: for (i, f) in data.fields.iter().enumerate() {
1380                let last = i == last_at;
1381                let ty = &f.ty;
1382                for attr in &f.attrs {
1383                    if attr_str(attr).as_deref() == Some("parse") {
1384                        let ParseArgs { unchecked, .. } = attr.parse_args::<ParseArgs>()?;
1385                        if unchecked {
1386                            continue 'field;
1387                        }
1388                    }
1389                }
1390                if u {
1391                    continue 'field;
1392                }
1393                let tr = tr(last);
1394                generics
1395                    .make_where_clause()
1396                    .predicates
1397                    .push(parse_quote_spanned! { ty.span() =>
1398                        #ty: #tr
1399                    });
1400            }
1401        }
1402        Data::Enum(data) => {
1403            for v in data.variants.iter() {
1404                let last_at = v.fields.len().saturating_sub(1);
1405                'field: for (i, f) in v.fields.iter().enumerate() {
1406                    let ty = &f.ty;
1407                    for attr in &f.attrs {
1408                        if attr_str(attr).as_deref() == Some("parse") {
1409                            let ParseArgs { unchecked, .. } = attr.parse_args::<ParseArgs>()?;
1410                            if unchecked {
1411                                continue 'field;
1412                            }
1413                        }
1414                    }
1415                    if u {
1416                        continue 'field;
1417                    }
1418                    let last = i == last_at;
1419                    let tr = tr(last);
1420                    generics.make_where_clause().predicates.push(
1421                        parse_quote_spanned! { ty.span() =>
1422                            #ty: #tr
1423                        },
1424                    );
1425                }
1426            }
1427        }
1428        Data::Union(data) => {
1429            return Err(Error::new_spanned(
1430                data.union_token,
1431                "`union`s are not supported",
1432            ));
1433        }
1434    }
1435    generics.params.push(if recursive {
1436        parse_quote!(#inp: ::object_rainbow::PointInput<
1437            Extra: ::core::marker::Send + ::core::marker::Sync + ::core::clone::Clone
1438        >)
1439    } else {
1440        parse_quote!(#inp: ::object_rainbow::ParseInput)
1441    });
1442    for bound in wheres {
1443        generics.make_where_clause().predicates.push(bound);
1444    }
1445    generics.params.extend(ig);
1446    Ok((inp, generics))
1447}
1448
1449fn gen_parse(
1450    data: &Data,
1451    attrs: &[Attribute],
1452) -> (proc_macro2::TokenStream, Option<proc_macro2::TokenStream>) {
1453    match parse_untagged(attrs) {
1454        Ok(None) => {}
1455        Ok(Some(untagged)) => {
1456            return (
1457                syn::Error::new(untagged.span(), "`untagged` cannot be parsed")
1458                    .into_compile_error(),
1459                None,
1460            );
1461        }
1462        Err(e) => return (e.into_compile_error(), None),
1463    };
1464    match data {
1465        Data::Struct(data) => {
1466            let arm = fields_parse(&data.fields);
1467            (quote! { Ok(Self #arm)}, None)
1468        }
1469        Data::Enum(data) => {
1470            let parse = data.variants.iter().map(|v| {
1471                let ident = &v.ident;
1472                let arm = fields_parse(&v.fields);
1473                quote! {
1474                    <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
1475                }
1476            });
1477            (
1478                quote! {
1479                    ::object_rainbow::enumkind::EnumParse::parse_as_enum(input)
1480                },
1481                Some(if data.variants.is_empty() {
1482                    quote! {
1483                        match kind {}
1484                    }
1485                } else {
1486                    quote! {
1487                        Ok(match kind {
1488                            #(#parse)*
1489                        })
1490                    }
1491                }),
1492            )
1493        }
1494        Data::Union(data) => (
1495            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error(),
1496            None,
1497        ),
1498    }
1499}
1500
1501fn fields_parse(fields: &syn::Fields) -> proc_macro2::TokenStream {
1502    let last_at = fields.len().saturating_sub(1);
1503    match fields {
1504        syn::Fields::Named(fields) => {
1505            let parse = fields.named.iter().enumerate().map(|(i, f)| {
1506                let last = i == last_at;
1507                let mut w = None;
1508                for attr in &f.attrs {
1509                    if attr_str(attr).as_deref() == Some("parse") {
1510                        let ParseArgs { with, .. } = match attr.parse_args::<ParseArgs>() {
1511                            Ok(args) => args,
1512                            Err(e) => return e.into_compile_error(),
1513                        };
1514                        if let Some(with) = with {
1515                            w = Some(with);
1516                        }
1517                    }
1518                }
1519                let i = f.ident.as_ref().unwrap();
1520                if let Some(with) = w {
1521                    let arg = if last {
1522                        quote!(input)
1523                    } else {
1524                        quote!(&mut input)
1525                    };
1526                    quote_spanned! { f.ty.span() =>
1527                        #i: #with(#arg)?
1528                    }
1529                } else {
1530                    let method = if last {
1531                        quote!(parse)
1532                    } else {
1533                        quote!(parse_inline)
1534                    };
1535                    quote_spanned! { f.ty.span() =>
1536                        #i: input.#method()?
1537                    }
1538                }
1539            });
1540            quote! { { #(#parse),* } }
1541        }
1542        syn::Fields::Unnamed(fields) => {
1543            let parse = fields.unnamed.iter().enumerate().map(|(i, f)| {
1544                let mut w = None;
1545                for attr in &f.attrs {
1546                    if attr_str(attr).as_deref() == Some("parse") {
1547                        let ParseArgs { with, .. } = match attr.parse_args::<ParseArgs>() {
1548                            Ok(args) => args,
1549                            Err(e) => return e.into_compile_error(),
1550                        };
1551                        if let Some(with) = with {
1552                            w = Some(with);
1553                        }
1554                    }
1555                }
1556                let last = i == last_at;
1557                if let Some(with) = w {
1558                    let arg = if last {
1559                        quote!(input)
1560                    } else {
1561                        quote!(&mut input)
1562                    };
1563                    quote_spanned! { f.ty.span() =>
1564                        #with(#arg)?
1565                    }
1566                } else {
1567                    let method = if last {
1568                        quote!(parse)
1569                    } else {
1570                        quote!(parse_inline)
1571                    };
1572                    quote_spanned! { f.ty.span() =>
1573                        input.#method()?
1574                    }
1575                }
1576            });
1577            quote! { (#(#parse),*) }
1578        }
1579        syn::Fields::Unit => quote! {},
1580    }
1581}
1582
1583/// ```rust
1584/// use object_rainbow::{Parse, ParseInline, ParseInput};
1585///
1586/// #[derive(Parse, ParseInline)]
1587/// struct Three<A, B, C> {
1588///     a: A,
1589///     b: B,
1590///     c: C,
1591/// }
1592///
1593/// object_rainbow::assert_impl!(
1594///     impl<A, B, C, I> ParseInline<I> for Three<A, B, C>
1595///     where
1596///         A: ParseInline<I>,
1597///         B: ParseInline<I>,
1598///         C: ParseInline<I>,
1599///         I: ParseInput,
1600///     {}
1601/// );
1602/// ```
1603#[proc_macro_derive(ParseInline, attributes(parse))]
1604pub fn derive_parse_inline(input: TokenStream) -> TokenStream {
1605    let input = parse_macro_input!(input as DeriveInput);
1606    let name = input.ident;
1607    let generics = input.generics.clone();
1608    let (_, ty_generics, _) = generics.split_for_impl();
1609    let (inp, generics) = match bounds_parse_inline(input.generics, &input.data, &input.attrs) {
1610        Ok(g) => g,
1611        Err(e) => return e.into_compile_error().into(),
1612    };
1613    let (parse_inline, enum_parse_inline) = gen_parse_inline(&input.data);
1614    let (impl_generics, _, where_clause) = generics.split_for_impl();
1615    let target = parse_for(&name, &input.attrs);
1616    let enum_parse_inline = enum_parse_inline.map(|enum_parse_inline| {
1617        quote! {
1618            #[automatically_derived]
1619            impl #impl_generics ::object_rainbow::enumkind::EnumParseInline<#inp>
1620            for #target #ty_generics #where_clause {
1621                fn enum_parse_inline(
1622                    kind: <Self as ::object_rainbow::Enum>::Kind, input: &mut #inp,
1623                ) -> ::object_rainbow::Result<Self> {
1624                    #enum_parse_inline
1625                }
1626            }
1627        }
1628    });
1629    let output = quote! {
1630        #[automatically_derived]
1631        impl #impl_generics ::object_rainbow::ParseInline<#inp>
1632        for #target #ty_generics #where_clause {
1633            fn parse_inline(input: &mut #inp) -> ::object_rainbow::Result<Self> {
1634                #parse_inline
1635            }
1636        }
1637
1638        #enum_parse_inline
1639    };
1640    TokenStream::from(output)
1641}
1642
1643fn bounds_parse_inline(
1644    mut generics: Generics,
1645    data: &Data,
1646    attrs: &[Attribute],
1647) -> syn::Result<(Ident, Generics)> {
1648    let (recursive, _, _, _) = parse_recursive_inline(attrs)?;
1649    let (u, inp, wheres, ig) = parse_parse_args(attrs)?;
1650    let tr = if recursive {
1651        quote!(::object_rainbow::ParseInline<#inp> + ::object_rainbow::Inline<#inp::Extra>)
1652    } else {
1653        quote!(::object_rainbow::ParseInline<#inp>)
1654    };
1655    match data {
1656        Data::Struct(data) => {
1657            'field: for f in data.fields.iter() {
1658                let ty = &f.ty;
1659                for attr in &f.attrs {
1660                    if attr_str(attr).as_deref() == Some("parse") {
1661                        let ParseArgs { unchecked, .. } = attr.parse_args::<ParseArgs>()?;
1662                        if unchecked {
1663                            continue 'field;
1664                        }
1665                    }
1666                }
1667                if u {
1668                    continue 'field;
1669                }
1670                generics
1671                    .make_where_clause()
1672                    .predicates
1673                    .push(parse_quote_spanned! { ty.span() =>
1674                        #ty: #tr
1675                    });
1676            }
1677        }
1678        Data::Enum(data) => {
1679            for v in data.variants.iter() {
1680                'field: for f in v.fields.iter() {
1681                    let ty = &f.ty;
1682                    for attr in &f.attrs {
1683                        if attr_str(attr).as_deref() == Some("parse") {
1684                            let ParseArgs { unchecked, .. } = attr.parse_args::<ParseArgs>()?;
1685                            if unchecked {
1686                                continue 'field;
1687                            }
1688                        }
1689                    }
1690                    if u {
1691                        continue 'field;
1692                    }
1693                    generics.make_where_clause().predicates.push(
1694                        parse_quote_spanned! { ty.span() =>
1695                            #ty: #tr
1696                        },
1697                    );
1698                }
1699            }
1700        }
1701        Data::Union(data) => {
1702            return Err(Error::new_spanned(
1703                data.union_token,
1704                "`union`s are not supported",
1705            ));
1706        }
1707    }
1708    generics.params.push(if recursive {
1709        parse_quote!(#inp: ::object_rainbow::PointInput<
1710            Extra: ::core::marker::Send + ::core::marker::Sync
1711        >)
1712    } else {
1713        parse_quote!(#inp: ::object_rainbow::ParseInput)
1714    });
1715    for bound in wheres {
1716        generics.make_where_clause().predicates.push(bound);
1717    }
1718    for generic in ig {
1719        generics.params.push(parse_quote!(#generic));
1720    }
1721    Ok((inp, generics))
1722}
1723
1724fn fields_parse_inline(fields: &syn::Fields) -> proc_macro2::TokenStream {
1725    match fields {
1726        syn::Fields::Named(fields) => {
1727            let parse = fields.named.iter().map(|f| {
1728                let i = f.ident.as_ref().unwrap();
1729                quote_spanned! { f.ty.span() =>
1730                    #i: input.parse_inline()?
1731                }
1732            });
1733            quote! { { #(#parse),* } }
1734        }
1735        syn::Fields::Unnamed(fields) => {
1736            let parse = fields.unnamed.iter().map(|f| {
1737                quote_spanned! { f.ty.span() =>
1738                    input.parse_inline()?
1739                }
1740            });
1741            quote! { (#(#parse),*) }
1742        }
1743        syn::Fields::Unit => quote! {},
1744    }
1745}
1746
1747fn gen_parse_inline(data: &Data) -> (proc_macro2::TokenStream, Option<proc_macro2::TokenStream>) {
1748    match data {
1749        Data::Struct(data) => {
1750            let arm = fields_parse_inline(&data.fields);
1751            (quote! { Ok(Self #arm) }, None)
1752        }
1753        Data::Enum(data) => {
1754            let parse_inline = data.variants.iter().map(|v| {
1755                let ident = &v.ident;
1756                let arm = fields_parse_inline(&v.fields);
1757                quote! {
1758                    <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
1759                }
1760            });
1761            (
1762                quote! {
1763                    ::object_rainbow::enumkind::EnumParseInline::parse_as_inline_enum(input)
1764                },
1765                Some(if data.variants.is_empty() {
1766                    quote! {
1767                        match kind {}
1768                    }
1769                } else {
1770                    quote! {
1771                        Ok(match kind {
1772                            #(#parse_inline)*
1773                        })
1774                    }
1775                }),
1776            )
1777        }
1778        Data::Union(data) => (
1779            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error(),
1780            None,
1781        ),
1782    }
1783}
1784
1785/// ```rust
1786/// use object_rainbow::{Parse, ParseAsInline, ParseInline, ParseInput};
1787///
1788/// #[derive(ParseAsInline)]
1789/// struct Thing<T> {
1790///     inner: T,
1791/// }
1792///
1793/// object_rainbow::assert_impl!(
1794///     impl<T, I> Parse<I> for Thing<T>
1795///     where
1796///         Thing<T>: ParseInline<I>,
1797///         I: ParseInput,
1798///     {}
1799/// );
1800/// ```
1801#[proc_macro_derive(ParseAsInline)]
1802pub fn derive_parse_as_inline(input: TokenStream) -> TokenStream {
1803    let input = parse_macro_input!(input as DeriveInput);
1804    let name = input.ident;
1805    let generics = input.generics.clone();
1806    let (_, ty_generics, _) = generics.split_for_impl();
1807    let generics = match bounds_parse_as_inline(input.generics, &name) {
1808        Ok(g) => g,
1809        Err(e) => return e.into_compile_error().into(),
1810    };
1811    let (impl_generics, _, where_clause) = generics.split_for_impl();
1812    let target = parse_for(&name, &input.attrs);
1813    let output = quote! {
1814        #[automatically_derived]
1815        impl #impl_generics ::object_rainbow::Parse<__I> for #target #ty_generics #where_clause {
1816            fn parse(input: __I) -> ::object_rainbow::Result<Self> {
1817                ::object_rainbow::ParseInline::<__I>::parse_as_inline(input)
1818            }
1819        }
1820    };
1821    TokenStream::from(output)
1822}
1823
1824fn bounds_parse_as_inline(mut generics: Generics, name: &Ident) -> syn::Result<Generics> {
1825    generics
1826        .make_where_clause()
1827        .predicates
1828        .push(parse_quote_spanned! { name.span() =>
1829            Self: ::object_rainbow::ParseInline::<__I>
1830        });
1831    generics
1832        .params
1833        .push(parse_quote!(__I: ::object_rainbow::ParseInput));
1834    Ok(generics)
1835}
1836
1837fn parse_path(attr: &Attribute) -> syn::Result<Type> {
1838    attr.parse_args::<LitStr>()?.parse()
1839}
1840
1841fn attr_str(attr: &Attribute) -> Option<String> {
1842    Some(attr.path().get_ident()?.to_string())
1843}
1844
1845/// ```rust
1846/// use std::num::NonZero;
1847///
1848/// use object_rainbow::{Enum, MaybeHasNiche, ToOutput};
1849///
1850/// #[derive(Enum, ToOutput, MaybeHasNiche)]
1851/// enum WithDefault {
1852///     A(u8),
1853///     B(bool),
1854/// }
1855///
1856/// assert_eq!(Some(WithDefault::A(32)).vec(), [0, 32]);
1857/// assert_eq!(Some(WithDefault::B(true)).vec(), [1, 1]);
1858/// assert_eq!(None::<WithDefault>.vec(), [2, 0]);
1859///
1860/// #[derive(Enum, ToOutput, MaybeHasNiche)]
1861/// #[enumtag("NonZero<u8>")]
1862/// enum WithNz {
1863///     A(u8),
1864///     B(bool),
1865/// }
1866///
1867/// assert_eq!(None::<WithNz>.vec(), [0, 0]);
1868/// assert_eq!(Some(WithNz::A(32)).vec(), [1, 32]);
1869/// assert_eq!(Some(WithNz::B(true)).vec(), [2, 1]);
1870///
1871/// #[derive(Enum, ToOutput, MaybeHasNiche)]
1872/// #[enumtag("bool")]
1873/// enum WithBool {
1874///     A(u8),
1875///     B(bool),
1876/// }
1877///
1878/// assert_eq!(Some(WithBool::A(32)).vec(), [0, 32]);
1879/// assert_eq!(Some(WithBool::B(true)).vec(), [1, 1]);
1880/// assert_eq!(None::<WithBool>.vec(), [2, 0]);
1881///
1882/// #[derive(Enum, ToOutput, MaybeHasNiche)]
1883/// #[enumtag("u8")]
1884/// enum WithU8 {
1885///     A(u8),
1886///     B(bool),
1887/// }
1888///
1889/// assert_eq!(Some(WithU8::A(32)).vec(), [0, 32]);
1890/// assert_eq!(Some(WithU8::B(true)).vec(), [1, 1]);
1891/// assert_eq!(None::<WithU8>.vec(), [1, 2]);
1892///
1893/// #[derive(Enum, ToOutput, MaybeHasNiche)]
1894/// #[enumtag("u8")]
1895/// enum WithoutNiche {
1896///     A(u8),
1897///     B(u8),
1898/// }
1899///
1900/// assert_eq!(Some(WithoutNiche::A(32)).vec(), [0, 0, 32]);
1901/// assert_eq!(Some(WithoutNiche::B(1)).vec(), [0, 1, 1]);
1902/// assert_eq!(None::<WithoutNiche>.vec(), [1]);
1903///
1904/// #[derive(Enum, ToOutput, MaybeHasNiche)]
1905/// #[enumtag("bool")]
1906/// #[niche(tag)]
1907/// enum WithBoolTag {
1908///     A(u8),
1909///     B(bool),
1910/// }
1911///
1912/// assert_eq!(Some(WithBoolTag::A(32)).vec(), [0, 32]);
1913/// assert_eq!(Some(WithBoolTag::B(true)).vec(), [1, 1]);
1914/// assert_eq!(None::<WithBoolTag>.vec(), [2]);
1915///
1916/// #[derive(Enum, ToOutput, MaybeHasNiche)]
1917/// #[enumtag("char")]
1918/// #[niche(tag)]
1919/// enum WithChar {
1920///     A(u8),
1921///     B(bool),
1922/// }
1923///
1924/// assert_eq!(Some(WithChar::A(32)).vec(), [0, 32]);
1925/// assert_eq!(Some(WithChar::B(true)).vec(), [1, 1]);
1926/// assert_eq!(None::<WithChar>.vec(), [255]);
1927/// ```
1928#[proc_macro_derive(Enum, attributes(enumtag))]
1929pub fn derive_enum(input: TokenStream) -> TokenStream {
1930    let input = parse_macro_input!(input as DeriveInput);
1931    let name = input.ident;
1932    let generics = input.generics.clone();
1933    let (_, ty_generics, _) = generics.split_for_impl();
1934    let generics = input.generics;
1935    let length = gen_length(&input.data);
1936    let variants = gen_variants(&input.data);
1937    let variant_count = gen_variant_count(&input.data);
1938    let to_tag = gen_to_tag(&input.data);
1939    let from_tag = gen_from_tag(&input.data);
1940    let kind = gen_kind(&input.data);
1941    let (impl_generics, _, where_clause) = generics.split_for_impl();
1942    let mut errors = Vec::new();
1943    let mut enumtag = None;
1944    for attr in &input.attrs {
1945        if attr_str(attr).as_deref() == Some("enumtag") {
1946            match parse_path(attr) {
1947                Ok(path) => {
1948                    if enumtag.is_some() {
1949                        errors.push(Error::new_spanned(path, "duplicate tag"));
1950                    } else {
1951                        enumtag = Some(path);
1952                    }
1953                }
1954                Err(e) => errors.push(e),
1955            }
1956        }
1957    }
1958    let enumtag = enumtag.unwrap_or_else(|| {
1959        parse_quote!(
1960            ::object_rainbow::partial_byte_tag::PartialByteTag<#length>
1961        )
1962    });
1963    let errors = errors.into_iter().map(|e| e.into_compile_error());
1964    let target = parse_for(&name, &input.attrs);
1965    let output = quote! {
1966        const _: () = {
1967            #(#errors)*
1968
1969            use ::object_rainbow::enumkind::EnumKind;
1970
1971            #[derive(Clone, Copy, ::object_rainbow::ParseAsInline)]
1972            pub enum __Kind {
1973                #variants
1974            }
1975
1976            #[automatically_derived]
1977            impl ::object_rainbow::enumkind::EnumKind for __Kind {
1978                type Tag = ::object_rainbow::enumkind::EnumTag<
1979                    #enumtag,
1980                    #variant_count,
1981                >;
1982
1983                fn to_tag(self) -> Self::Tag {
1984                    #to_tag
1985                }
1986
1987                fn from_tag(tag: Self::Tag) -> Self {
1988                    #from_tag
1989                }
1990            }
1991
1992            impl<I: ::object_rainbow::ParseInput> ::object_rainbow::ParseInline<I> for __Kind {
1993                fn parse_inline(input: &mut I) -> ::object_rainbow::Result<Self> {
1994                    Ok(::object_rainbow::enumkind::EnumKind::from_tag(input.parse_inline()?))
1995                }
1996            }
1997
1998            impl ::object_rainbow::MaybeHasNiche for __Kind {
1999                type MnArray = <#enumtag as ::object_rainbow::MaybeHasNiche>::MnArray;
2000            }
2001
2002            #[automatically_derived]
2003            impl #impl_generics ::object_rainbow::Enum for #target #ty_generics #where_clause {
2004                type Kind = __Kind;
2005
2006                fn kind(&self) -> Self::Kind {
2007                    #kind
2008                }
2009            }
2010        };
2011    };
2012    TokenStream::from(output)
2013}
2014
2015fn gen_length(data: &Data) -> proc_macro2::TokenStream {
2016    match data {
2017        Data::Struct(data) => {
2018            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2019        }
2020        Data::Enum(data) => {
2021            let name = format!("U{}", data.variants.len());
2022            let ident = Ident::new(&name, data.variants.span());
2023            quote! { ::object_rainbow::typenum::#ident }
2024        }
2025        Data::Union(data) => {
2026            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2027        }
2028    }
2029}
2030
2031fn gen_variants(data: &Data) -> proc_macro2::TokenStream {
2032    match data {
2033        Data::Struct(data) => {
2034            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2035        }
2036        Data::Enum(data) => {
2037            let variants = data.variants.iter().map(|v| &v.ident);
2038            quote! { #(#variants),* }
2039        }
2040        Data::Union(data) => {
2041            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2042        }
2043    }
2044}
2045
2046fn gen_variant_count(data: &Data) -> proc_macro2::TokenStream {
2047    match data {
2048        Data::Struct(data) => {
2049            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2050        }
2051        Data::Enum(data) => {
2052            let variant_count = data.variants.len();
2053            quote! { #variant_count }
2054        }
2055        Data::Union(data) => {
2056            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2057        }
2058    }
2059}
2060
2061fn gen_to_tag(data: &Data) -> proc_macro2::TokenStream {
2062    match data {
2063        Data::Struct(data) => {
2064            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2065        }
2066        Data::Enum(data) => {
2067            let to_tag = data.variants.iter().enumerate().map(|(i, v)| {
2068                let ident = &v.ident;
2069                quote_spanned! { ident.span() =>
2070                    Self::#ident => ::object_rainbow::enumkind::EnumTag::from_const::<#i>(),
2071                }
2072            });
2073            quote! {
2074                match self {
2075                    #(#to_tag)*
2076                }
2077            }
2078        }
2079        Data::Union(data) => {
2080            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2081        }
2082    }
2083}
2084
2085fn gen_from_tag(data: &Data) -> proc_macro2::TokenStream {
2086    match data {
2087        Data::Struct(data) => {
2088            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2089        }
2090        Data::Enum(data) => {
2091            let from_tag = data.variants.iter().enumerate().map(|(i, v)| {
2092                let ident = &v.ident;
2093                quote_spanned! { ident.span() =>
2094                    #i => Self::#ident,
2095                }
2096            });
2097            quote! {
2098                match tag.to_usize() {
2099                    #(#from_tag)*
2100                    _ => unreachable!(),
2101                }
2102            }
2103        }
2104        Data::Union(data) => {
2105            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2106        }
2107    }
2108}
2109
2110fn gen_kind(data: &Data) -> proc_macro2::TokenStream {
2111    match data {
2112        Data::Struct(data) => {
2113            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2114        }
2115        Data::Enum(data) => {
2116            if data.variants.is_empty() {
2117                return quote! {
2118                    match *self {}
2119                };
2120            }
2121            let variants = data.variants.iter().map(|v| {
2122                let ident = &v.ident;
2123                quote_spanned! { ident.span() =>
2124                    Self::#ident {..} => __Kind::#ident,
2125                }
2126            });
2127            quote! {
2128                match self {
2129                    #(#variants)*
2130                }
2131            }
2132        }
2133        Data::Union(data) => {
2134            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2135        }
2136    }
2137}
2138
2139/// ```rust
2140/// use object_rainbow::{MaybeHasNiche, Size};
2141///
2142/// #[derive(Size, MaybeHasNiche)]
2143/// struct WithHole(bool, u8);
2144///
2145/// #[derive(Size, MaybeHasNiche)]
2146/// struct NoHole(u8, u8);
2147///
2148/// assert_eq!(Option::<WithHole>::SIZE, 2);
2149/// assert_eq!(Option::<(object_rainbow::ff::Ff, NoHole)>::SIZE, 3);
2150/// ```
2151#[proc_macro_derive(MaybeHasNiche, attributes(niche))]
2152pub fn derive_maybe_has_niche(input: TokenStream) -> TokenStream {
2153    let input = parse_macro_input!(input as DeriveInput);
2154    let name = input.ident;
2155    let mn_array = gen_mn_array(&input.data, &input.attrs);
2156    let (_, ty_generics, _) = input.generics.split_for_impl();
2157    let generics = match bounds_maybe_has_niche(input.generics.clone(), &input.data, &input.attrs) {
2158        Ok(g) => g,
2159        Err(e) => return e.into_compile_error().into(),
2160    };
2161    let (impl_generics, _, where_clause) = generics.split_for_impl();
2162    let target = parse_for(&name, &input.attrs);
2163    let output = quote! {
2164        const _: () = {
2165            use ::object_rainbow::typenum::tarr;
2166
2167            #[automatically_derived]
2168            impl #impl_generics ::object_rainbow::MaybeHasNiche
2169            for #target #ty_generics #where_clause {
2170                type MnArray = #mn_array;
2171            }
2172        };
2173    };
2174    TokenStream::from(output)
2175}
2176
2177#[derive(Debug, FromMeta)]
2178#[darling(derive_syn_parse)]
2179struct ContainerNicheArgs {
2180    #[darling(default)]
2181    tag: bool,
2182}
2183
2184fn parse_niche_tag(attrs: &[Attribute]) -> syn::Result<bool> {
2185    let mut t = false;
2186    for attr in attrs {
2187        if attr_str(attr).as_deref() == Some("niche") {
2188            let ContainerNicheArgs { tag } = attr.parse_args()?;
2189            if tag {
2190                t = true;
2191            }
2192        }
2193    }
2194    Ok(t)
2195}
2196
2197fn bounds_maybe_has_niche(
2198    mut generics: Generics,
2199    data: &Data,
2200    attrs: &[Attribute],
2201) -> syn::Result<Generics> {
2202    let tag = parse_niche_tag(attrs)?;
2203    match data {
2204        Data::Struct(data) => {
2205            for f in data.fields.iter() {
2206                let ty = &f.ty;
2207                generics
2208                    .make_where_clause()
2209                    .predicates
2210                    .push(parse_quote_spanned! { ty.span() =>
2211                        #ty: ::object_rainbow::MaybeHasNiche<
2212                            MnArray: ::object_rainbow::MnArray<
2213                                MaybeNiche: ::object_rainbow::MaybeNiche
2214                            >
2215                        >
2216                    });
2217            }
2218        }
2219        Data::Enum(data) => {
2220            if tag {
2221                return Ok(generics);
2222            }
2223            generics.params.push(parse_quote!(
2224                __N: ::object_rainbow::typenum::Unsigned
2225            ));
2226            for (i, v) in data.variants.iter().enumerate() {
2227                let mn_array = fields_mn_array(&v.fields, Some(i));
2228                generics
2229                    .make_where_clause()
2230                    .predicates
2231                    .push(parse_quote_spanned! { v.span() =>
2232                        #mn_array: ::object_rainbow::MnArray<
2233                            MaybeNiche: ::object_rainbow::NicheOr<N = __N>
2234                        >
2235                    });
2236                for f in v.fields.iter() {
2237                    let ty = &f.ty;
2238                    generics.make_where_clause().predicates.push(
2239                        parse_quote_spanned! { ty.span() =>
2240                            #ty: ::object_rainbow::MaybeHasNiche<
2241                                MnArray: ::object_rainbow::MnArray<
2242                                    MaybeNiche: ::object_rainbow::MaybeNiche
2243                                >
2244                            >
2245                        },
2246                    );
2247                }
2248            }
2249        }
2250        Data::Union(data) => {
2251            return Err(Error::new_spanned(
2252                data.union_token,
2253                "`union`s are not supported",
2254            ));
2255        }
2256    }
2257    Ok(generics)
2258}
2259
2260fn fields_mn_array(fields: &syn::Fields, variant: Option<usize>) -> proc_macro2::TokenStream {
2261    let mn_array = fields.iter().map(|f| {
2262        let ty = &f.ty;
2263        quote! {
2264            <
2265                <
2266                    #ty
2267                    as
2268                    ::object_rainbow::MaybeHasNiche
2269                >::MnArray
2270                as
2271                ::object_rainbow::MnArray
2272            >::MaybeNiche
2273        }
2274    });
2275    if let Some(variant) = variant {
2276        let kind_niche = quote! {
2277            ::object_rainbow::AutoEnumNiche<Self, #variant>
2278        };
2279        quote! {
2280            tarr![
2281                #kind_niche,
2282                ::object_rainbow::NoNiche<::object_rainbow::HackNiche<#variant>>, #(#mn_array),*
2283            ]
2284        }
2285    } else {
2286        quote! { tarr![#(#mn_array),*] }
2287    }
2288}
2289
2290fn gen_mn_array(data: &Data, attrs: &[Attribute]) -> proc_macro2::TokenStream {
2291    let tag = match parse_niche_tag(attrs) {
2292        Ok(tag) => tag,
2293        Err(e) => return e.into_compile_error(),
2294    };
2295    match data {
2296        Data::Struct(data) => fields_mn_array(&data.fields, None),
2297        Data::Enum(data) => {
2298            if tag {
2299                return quote! {
2300                    <
2301                        <Self as ::object_rainbow::Enum>::Kind as ::object_rainbow::MaybeHasNiche
2302                    >::MnArray
2303                };
2304            }
2305            let mn_array = data.variants.iter().enumerate().map(|(i, v)| {
2306                let mn_array = fields_mn_array(&v.fields, Some(i));
2307                quote! { <#mn_array as ::object_rainbow::MnArray>::MaybeNiche }
2308            });
2309            quote! {
2310                ::object_rainbow::NicheFoldOrArray<tarr![#(#mn_array),*]>
2311            }
2312        }
2313        Data::Union(data) => {
2314            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
2315        }
2316    }
2317}
2318
2319#[proc_macro_attribute]
2320pub fn derive_for_wrapped(args: TokenStream, input: TokenStream) -> TokenStream {
2321    let input = parse_macro_input!(input as ItemTrait);
2322    let sup = if args.is_empty() {
2323        let sup = input.supertraits.clone();
2324        quote!(#sup)
2325    } else {
2326        args.into()
2327    };
2328    let name = input.ident.clone();
2329    let generics = input.generics.clone();
2330    let (_, ty_generics, _) = generics.split_for_impl();
2331    let mut derived = Vec::new();
2332    for (path, extra) in [
2333        (
2334            quote!(map_extra::MappedExtra),
2335            vec![(quote!(__M), quote!(#sup))],
2336        ),
2337        (quote!(length_prefixed::Lp), vec![]),
2338    ] {
2339        let mut generics = input.generics.clone();
2340        generics.params.push(parse_quote! {
2341            __T: #name #ty_generics
2342        });
2343        for (i, ty) in &extra {
2344            generics.params.push(parse_quote! {
2345                #i: #ty
2346            });
2347        }
2348        let (impl_generics, _, where_clause) = generics.split_for_impl();
2349        let i = input
2350            .items
2351            .clone()
2352            .into_iter()
2353            .map(|i| match i {
2354                TraitItem::Const(i) => ImplItem::Const({
2355                    let const_token = i.const_token;
2356                    let ident = i.ident;
2357                    let colon_token = i.colon_token;
2358                    let ty = i.ty;
2359                    let semi_token = i.semi_token;
2360                    parse_quote! {
2361                        #const_token
2362                        #ident
2363                        #colon_token
2364                        #ty
2365                        =
2366                        <__T as #name #ty_generics>::#ident
2367                        #semi_token
2368                    }
2369                }),
2370                TraitItem::Fn(i) => ImplItem::Fn({
2371                    let mut sig = i.sig;
2372                    let ident = sig.ident.clone();
2373                    let args = sig
2374                        .inputs
2375                        .iter_mut()
2376                        .enumerate()
2377                        .map(|(n, i)| match i {
2378                            FnArg::Receiver(receiver) => {
2379                                let reference = receiver.reference.as_ref().map(|(and, _)| and);
2380                                let mutability = receiver.mutability.as_ref();
2381                                let ident = &receiver.self_token;
2382                                quote!(#reference #mutability *#ident)
2383                            }
2384                            FnArg::Typed(pat_type) => {
2385                                let ident = Ident::new(&format!("arg{n}"), pat_type.span());
2386                                *pat_type.pat = parse_quote!(#ident);
2387                                quote!(#ident)
2388                            }
2389                        })
2390                        .collect::<Vec<_>>();
2391                    parse_quote! {
2392                        #sig
2393                        {
2394                            <__T as #name #ty_generics>::#ident(
2395                                #(#args),*
2396                            )
2397                        }
2398                    }
2399                }),
2400                TraitItem::Type(i) => ImplItem::Type({
2401                    let type_token = i.type_token;
2402                    let ident = i.ident;
2403                    let semi_token = i.semi_token;
2404                    parse_quote! {
2405                        #type_token
2406                        #ident
2407                        =
2408                        <__T as #name #ty_generics>::#ident
2409                        #semi_token
2410                    }
2411                }),
2412                _ => unimplemented!("unknown/unsupported item"),
2413            })
2414            .collect::<Vec<_>>();
2415        let extra = extra.into_iter().map(|(k, _)| k);
2416        derived.push(quote! {
2417            impl #impl_generics #name #ty_generics for ::object_rainbow::#path<
2418                __T,
2419                #(#extra),*
2420            >
2421            #where_clause
2422            {
2423                #(#i)*
2424            }
2425        });
2426    }
2427    let output = quote! {
2428        #input
2429
2430        #(#derived)*
2431    };
2432    output.into()
2433}