object_rainbow_derive/
lib.rs

1use std::collections::BTreeSet;
2
3use proc_macro::TokenStream;
4use quote::{quote, quote_spanned};
5use syn::{
6    Attribute, Data, DeriveInput, Error, GenericParam, Generics, Ident, LitStr, Type, parse::Parse,
7    parse_macro_input, parse_quote, parse_quote_spanned, spanned::Spanned, token::Comma,
8};
9
10use self::contains_generics::{GContext, type_contains_generics};
11
12mod contains_generics;
13
14fn bounds_g(generics: &Generics) -> BTreeSet<Ident> {
15    generics
16        .params
17        .iter()
18        .filter_map(|param| match param {
19            GenericParam::Lifetime(_) => None,
20            GenericParam::Type(param) => Some(&param.ident),
21            GenericParam::Const(param) => Some(&param.ident),
22        })
23        .cloned()
24        .collect()
25}
26
27#[proc_macro_derive(ToOutput)]
28pub fn derive_to_output(input: TokenStream) -> TokenStream {
29    let input = parse_macro_input!(input as DeriveInput);
30    let name = input.ident;
31    let generics = match bounds_to_output(input.generics, &input.data) {
32        Ok(g) => g,
33        Err(e) => return e.into_compile_error().into(),
34    };
35    let to_output = gen_to_output(&input.data);
36    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
37    let output = quote! {
38        #[automatically_derived]
39        impl #impl_generics ::object_rainbow::ToOutput for #name #ty_generics #where_clause {
40            fn to_output(&self, output: &mut dyn ::object_rainbow::Output) {
41                #to_output
42            }
43        }
44    };
45    TokenStream::from(output)
46}
47
48fn bounds_to_output(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
49    let g = &bounds_g(&generics);
50    match data {
51        Data::Struct(data) => {
52            for f in data.fields.iter() {
53                let ty = &f.ty;
54                if type_contains_generics(GContext { g, points: false }, ty) {
55                    generics.make_where_clause().predicates.push(
56                        parse_quote_spanned! { ty.span() =>
57                            #ty: ::object_rainbow::ToOutput
58                        },
59                    );
60                }
61            }
62        }
63        Data::Enum(data) => {
64            for v in data.variants.iter() {
65                for f in v.fields.iter() {
66                    let ty = &f.ty;
67                    if type_contains_generics(GContext { g, points: false }, ty) {
68                        generics.make_where_clause().predicates.push(
69                            parse_quote_spanned! { ty.span() =>
70                                #ty: ::object_rainbow::ToOutput
71                            },
72                        );
73                    }
74                }
75            }
76        }
77        Data::Union(data) => {
78            return Err(Error::new_spanned(
79                data.union_token,
80                "`union`s are not supported",
81            ));
82        }
83    }
84    Ok(generics)
85}
86
87fn fields_to_output(fields: &syn::Fields) -> proc_macro2::TokenStream {
88    match fields {
89        syn::Fields::Named(fields) => {
90            let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
91            let to_output = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
92                quote_spanned! { f.ty.span() =>
93                    #i.to_output(output)
94                }
95            });
96            quote! {
97                { #(#let_self),* } => {
98                    #(#to_output);*
99                }
100            }
101        }
102        syn::Fields::Unnamed(fields) => {
103            let let_self = fields
104                .unnamed
105                .iter()
106                .enumerate()
107                .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
108            let to_output = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
109                quote_spanned! { f.ty.span() =>
110                    #i.to_output(output)
111                }
112            });
113            quote! {
114                (#(#let_self),*) => {
115                    #(#to_output);*
116                }
117            }
118        }
119        syn::Fields::Unit => quote! {
120            => {}
121        },
122    }
123}
124
125fn gen_to_output(data: &Data) -> proc_macro2::TokenStream {
126    match data {
127        Data::Struct(data) => {
128            let arm = fields_to_output(&data.fields);
129            quote! {
130                match self {
131                    Self #arm
132                }
133            }
134        }
135        Data::Enum(data) => {
136            let to_output = data.variants.iter().map(|v| {
137                let ident = &v.ident;
138                let arm = fields_to_output(&v.fields);
139                quote! { Self::#ident #arm }
140            });
141            quote! {
142                let kind = ::object_rainbow::Enum::kind(self);
143                let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
144                tag.to_output(output);
145                match self {
146                    #(#to_output)*
147                }
148            }
149        }
150        Data::Union(data) => {
151            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
152        }
153    }
154}
155
156#[proc_macro_derive(Topological)]
157pub fn derive_topological(input: TokenStream) -> TokenStream {
158    let input = parse_macro_input!(input as DeriveInput);
159    let name = input.ident;
160    let generics = input.generics.clone();
161    let (_, ty_generics, _) = generics.split_for_impl();
162    let generics = match bounds_topological(input.generics, &input.data) {
163        Ok(g) => g,
164        Err(e) => return e.into_compile_error().into(),
165    };
166    let accept_points = gen_accept_points(&input.data);
167    let (impl_generics, _, where_clause) = generics.split_for_impl();
168    let output = quote! {
169        #[automatically_derived]
170        impl #impl_generics ::object_rainbow::Topological<__E> for #name #ty_generics #where_clause {
171            fn accept_points(&self, visitor: &mut impl ::object_rainbow::PointVisitor<__E>) {
172                #accept_points
173            }
174        }
175    };
176    TokenStream::from(output)
177}
178
179fn bounds_topological(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
180    let g = &bounds_g(&generics);
181    match data {
182        Data::Struct(data) => {
183            for f in data.fields.iter() {
184                let ty = &f.ty;
185                if type_contains_generics(GContext { g, points: true }, ty) {
186                    generics.make_where_clause().predicates.push(
187                        parse_quote_spanned! { ty.span() =>
188                            #ty: ::object_rainbow::Topological<__E>
189                        },
190                    );
191                }
192            }
193        }
194        Data::Enum(data) => {
195            for v in data.variants.iter() {
196                for f in v.fields.iter() {
197                    let ty = &f.ty;
198                    if type_contains_generics(GContext { g, points: true }, ty) {
199                        generics.make_where_clause().predicates.push(
200                            parse_quote_spanned! { ty.span() =>
201                                #ty: ::object_rainbow::Topological<__E>
202                            },
203                        );
204                    }
205                }
206            }
207        }
208        Data::Union(data) => {
209            return Err(Error::new_spanned(
210                data.union_token,
211                "`union`s are not supported",
212            ));
213        }
214    }
215    generics.params.push(parse_quote!(__E: 'static));
216    Ok(generics)
217}
218
219fn fields_accept_points(fields: &syn::Fields) -> proc_macro2::TokenStream {
220    match fields {
221        syn::Fields::Named(fields) => {
222            let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
223            let accept_points = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
224                quote_spanned! { f.ty.span() =>
225                    #i.accept_points(visitor)
226                }
227            });
228            quote! {
229                { #(#let_self),* } => {
230                    #(#accept_points);*
231                }
232            }
233        }
234        syn::Fields::Unnamed(fields) => {
235            let let_self = fields
236                .unnamed
237                .iter()
238                .enumerate()
239                .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
240            let accept_points = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
241                quote_spanned! { f.ty.span() =>
242                    #i.accept_points(visitor)
243                }
244            });
245            quote! {
246                (#(#let_self),*) => {
247                    #(#accept_points);*
248                }
249            }
250        }
251        syn::Fields::Unit => quote! {
252            => {}
253        },
254    }
255}
256
257fn gen_accept_points(data: &Data) -> proc_macro2::TokenStream {
258    match data {
259        Data::Struct(data) => {
260            let arm = fields_accept_points(&data.fields);
261            quote! {
262                match self {
263                    Self #arm
264                }
265            }
266        }
267        Data::Enum(data) => {
268            let to_output = data.variants.iter().map(|v| {
269                let ident = &v.ident;
270                let arm = fields_accept_points(&v.fields);
271                quote! { Self::#ident #arm }
272            });
273            quote! {
274                let kind = ::object_rainbow::Enum::kind(self);
275                let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
276                tag.accept_points(visitor);
277                match self {
278                    #(#to_output)*
279                }
280            }
281        }
282        Data::Union(data) => {
283            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
284        }
285    }
286}
287
288#[proc_macro_derive(Tagged, attributes(tags))]
289pub fn derive_tagged(input: TokenStream) -> TokenStream {
290    let input = parse_macro_input!(input as DeriveInput);
291    let name = input.ident;
292    let mut errors = Vec::new();
293    let generics = match bounds_tagged(input.generics, &input.data, &mut errors) {
294        Ok(g) => g,
295        Err(e) => return e.into_compile_error().into(),
296    };
297    let tags = gen_tags(&input.data, &input.attrs, &mut errors);
298    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
299    let errors = errors.into_iter().map(|e| e.into_compile_error());
300    let output = quote! {
301        #(#errors)*
302
303        #[automatically_derived]
304        impl #impl_generics ::object_rainbow::Tagged for #name #ty_generics #where_clause {
305            const TAGS: ::object_rainbow::Tags = #tags;
306        }
307    };
308    TokenStream::from(output)
309}
310
311struct FieldTagArgs {
312    skip: bool,
313}
314
315impl Parse for FieldTagArgs {
316    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
317        let mut skip = false;
318        while !input.is_empty() {
319            let ident = input.parse::<Ident>()?;
320            if ident.to_string().as_str() != "skip" {
321                return Err(Error::new(ident.span(), "expected: skip"));
322            }
323            skip = true;
324            if !input.is_empty() {
325                input.parse::<Comma>()?;
326            }
327        }
328        Ok(Self { skip })
329    }
330}
331
332fn bounds_tagged(
333    mut generics: Generics,
334    data: &Data,
335    errors: &mut Vec<Error>,
336) -> syn::Result<Generics> {
337    let g = &bounds_g(&generics);
338    match data {
339        Data::Struct(data) => {
340            for f in data.fields.iter() {
341                let mut skip = false;
342                for attr in &f.attrs {
343                    if attr_str(attr).as_deref() == Some("tags") {
344                        match attr.parse_args::<FieldTagArgs>() {
345                            Ok(args) => skip |= args.skip,
346                            Err(e) => errors.push(e),
347                        }
348                    }
349                }
350                if !skip {
351                    let ty = &f.ty;
352                    if type_contains_generics(GContext { g, points: false }, ty) {
353                        generics.make_where_clause().predicates.push(
354                            parse_quote_spanned! { ty.span() =>
355                                #ty: ::object_rainbow::Tagged
356                            },
357                        );
358                    }
359                }
360            }
361        }
362        Data::Enum(data) => {
363            for v in data.variants.iter() {
364                for f in v.fields.iter() {
365                    let mut skip = false;
366                    for attr in &f.attrs {
367                        if attr_str(attr).as_deref() == Some("tags") {
368                            match attr.parse_args::<FieldTagArgs>() {
369                                Ok(args) => skip |= args.skip,
370                                Err(e) => errors.push(e),
371                            }
372                        }
373                    }
374                    if !skip {
375                        let ty = &f.ty;
376                        if type_contains_generics(GContext { g, points: false }, ty) {
377                            generics.make_where_clause().predicates.push(
378                                parse_quote_spanned! { ty.span() =>
379                                    #ty: ::object_rainbow::Tagged
380                                },
381                            );
382                        }
383                    }
384                }
385            }
386        }
387        Data::Union(data) => {
388            return Err(Error::new_spanned(
389                data.union_token,
390                "`union`s are not supported",
391            ));
392        }
393    }
394    Ok(generics)
395}
396
397struct StructTagArgs {
398    tags: Vec<LitStr>,
399}
400
401impl Parse for StructTagArgs {
402    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
403        let mut tags = Vec::new();
404        while !input.is_empty() {
405            let tag = input.parse::<LitStr>()?;
406            tags.push(tag);
407            if !input.is_empty() {
408                input.parse::<Comma>()?;
409            }
410        }
411        Ok(Self { tags })
412    }
413}
414
415fn fields_tags(fields: &syn::Fields) -> Vec<proc_macro2::TokenStream> {
416    fields
417        .iter()
418        .filter_map(|f| {
419            let mut skip = false;
420            for attr in &f.attrs {
421                if attr_str(attr).as_deref() == Some("tags") {
422                    skip |= attr.parse_args::<FieldTagArgs>().ok()?.skip;
423                }
424            }
425            let ty = &f.ty;
426            (!skip).then_some(quote! { <#ty as ::object_rainbow::Tagged>::TAGS })
427        })
428        .collect()
429}
430
431fn gen_tags(data: &Data, attrs: &[Attribute], errors: &mut Vec<Error>) -> proc_macro2::TokenStream {
432    match data {
433        Data::Struct(data) => {
434            let mut tags = Vec::new();
435            for attr in attrs {
436                if attr_str(attr).as_deref() == Some("tags") {
437                    match attr.parse_args::<StructTagArgs>() {
438                        Ok(mut args) => tags.append(&mut args.tags),
439                        Err(e) => errors.push(e),
440                    }
441                }
442            }
443            let nested = fields_tags(&data.fields);
444            if nested.len() == 1 && tags.is_empty() {
445                let nested = nested.into_iter().next().unwrap();
446                quote! {
447                    #nested
448                }
449            } else {
450                quote! {
451                    ::object_rainbow::Tags(&[#(#tags),*], &[#(&#nested),*])
452                }
453            }
454        }
455        Data::Enum(data) => {
456            let mut tags = Vec::new();
457            for attr in attrs {
458                if attr_str(attr).as_deref() == Some("tags") {
459                    match attr.parse_args::<StructTagArgs>() {
460                        Ok(mut args) => tags.append(&mut args.tags),
461                        Err(e) => errors.push(e),
462                    }
463                }
464            }
465            let mut nested: Vec<_> = data
466                .variants
467                .iter()
468                .flat_map(|v| fields_tags(&v.fields))
469                .collect();
470            let kind_tags = quote! {
471                <
472                    <
473                        <
474                            Self
475                            as
476                            ::object_rainbow::Enum
477                        >::Kind
478                        as
479                        ::object_rainbow::enumkind::EnumKind
480                    >::Tag
481                    as  ::object_rainbow::Tagged
482                >::TAGS
483            };
484            nested.insert(0, kind_tags);
485            if nested.len() == 1 && tags.is_empty() {
486                let nested = nested.into_iter().next().unwrap();
487                quote! {
488                    #nested
489                }
490            } else {
491                quote! {
492                    ::object_rainbow::Tags(&[#(#tags),*], &[#(&#nested),*])
493                }
494            }
495        }
496        Data::Union(data) => {
497            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
498        }
499    }
500}
501
502#[proc_macro_derive(Object)]
503pub fn derive_object(input: TokenStream) -> TokenStream {
504    let input = parse_macro_input!(input as DeriveInput);
505    let name = input.ident;
506    let generics = input.generics.clone();
507    let (_, ty_generics, _) = generics.split_for_impl();
508    let generics = match bounds_object(input.generics, &input.data) {
509        Ok(g) => g,
510        Err(e) => return e.into_compile_error().into(),
511    };
512    let (impl_generics, _, where_clause) = generics.split_for_impl();
513    let output = quote! {
514        #[automatically_derived]
515        impl #impl_generics ::object_rainbow::Object<__E> for #name #ty_generics #where_clause {}
516    };
517    TokenStream::from(output)
518}
519
520fn bounds_object(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
521    let g = &bounds_g(&generics);
522    match data {
523        Data::Struct(data) => {
524            let last_at = data.fields.len().checked_sub(1).unwrap_or_default();
525            for (i, f) in data.fields.iter().enumerate() {
526                let last = i == last_at;
527                let ty = &f.ty;
528                let tr = if last {
529                    quote!(::object_rainbow::Object<__E>)
530                } else {
531                    quote!(::object_rainbow::Inline<__E>)
532                };
533                if type_contains_generics(GContext { g, points: true }, ty) {
534                    generics.make_where_clause().predicates.push(
535                        parse_quote_spanned! { ty.span() =>
536                            #ty: #tr
537                        },
538                    );
539                }
540            }
541        }
542        Data::Enum(data) => {
543            for v in data.variants.iter() {
544                let last_at = v.fields.len().checked_sub(1).unwrap_or_default();
545                for (i, f) in v.fields.iter().enumerate() {
546                    let last = i == last_at;
547                    let ty = &f.ty;
548                    let tr = if last {
549                        quote!(::object_rainbow::Object<__E>)
550                    } else {
551                        quote!(::object_rainbow::Inline<__E>)
552                    };
553                    if type_contains_generics(GContext { g, points: true }, ty) {
554                        generics.make_where_clause().predicates.push(
555                            parse_quote_spanned! { ty.span() =>
556                                #ty: #tr
557                            },
558                        );
559                    }
560                }
561            }
562        }
563        Data::Union(data) => {
564            return Err(Error::new_spanned(
565                data.union_token,
566                "`union`s are not supported",
567            ));
568        }
569    }
570    generics.params.push(parse_quote!(__E: 'static));
571    Ok(generics)
572}
573
574#[proc_macro_derive(Inline)]
575pub fn derive_inline(input: TokenStream) -> TokenStream {
576    let input = parse_macro_input!(input as DeriveInput);
577    let name = input.ident;
578    let generics = input.generics.clone();
579    let (_, ty_generics, _) = generics.split_for_impl();
580    let generics = match bounds_inline(input.generics, &input.data) {
581        Ok(g) => g,
582        Err(e) => return e.into_compile_error().into(),
583    };
584    let (impl_generics, _, where_clause) = generics.split_for_impl();
585    let output = quote! {
586        #[automatically_derived]
587        impl #impl_generics ::object_rainbow::Inline<__E> for #name #ty_generics #where_clause {}
588    };
589    TokenStream::from(output)
590}
591
592fn bounds_inline(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
593    let g = &bounds_g(&generics);
594    match data {
595        Data::Struct(data) => {
596            for f in data.fields.iter() {
597                let ty = &f.ty;
598                if type_contains_generics(GContext { g, points: true }, ty) {
599                    generics.make_where_clause().predicates.push(
600                        parse_quote_spanned! { ty.span() =>
601                            #ty: ::object_rainbow::Inline<__E>
602                        },
603                    );
604                }
605            }
606        }
607        Data::Enum(data) => {
608            for v in data.variants.iter() {
609                for f in v.fields.iter() {
610                    let ty = &f.ty;
611                    if type_contains_generics(GContext { g, points: true }, ty) {
612                        generics.make_where_clause().predicates.push(
613                            parse_quote_spanned! { ty.span() =>
614                                #ty: ::object_rainbow::Inline<__E>
615                            },
616                        );
617                    }
618                }
619            }
620        }
621        Data::Union(data) => {
622            return Err(Error::new_spanned(
623                data.union_token,
624                "`union`s are not supported",
625            ));
626        }
627    }
628    generics.params.push(parse_quote!(__E: 'static));
629    Ok(generics)
630}
631
632#[proc_macro_derive(ReflessObject)]
633pub fn derive_refless_object(input: TokenStream) -> TokenStream {
634    let input = parse_macro_input!(input as DeriveInput);
635    let name = input.ident;
636    let generics = match bounds_refless_object(input.generics, &input.data) {
637        Ok(g) => g,
638        Err(e) => return e.into_compile_error().into(),
639    };
640    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
641    let output = quote! {
642        #[automatically_derived]
643        impl #impl_generics ::object_rainbow::ReflessObject for #name #ty_generics #where_clause {}
644    };
645    TokenStream::from(output)
646}
647
648fn bounds_refless_object(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
649    let g = &bounds_g(&generics);
650    match data {
651        Data::Struct(data) => {
652            let last_at = data.fields.len().checked_sub(1).unwrap_or_default();
653            for (i, f) in data.fields.iter().enumerate() {
654                let last = i == last_at;
655                let ty = &f.ty;
656                let tr = if last {
657                    quote!(::object_rainbow::ReflessObject)
658                } else {
659                    quote!(::object_rainbow::ReflessInline)
660                };
661                if type_contains_generics(GContext { g, points: false }, ty) {
662                    generics.make_where_clause().predicates.push(
663                        parse_quote_spanned! { ty.span() =>
664                            #ty: #tr
665                        },
666                    );
667                }
668            }
669        }
670        Data::Enum(data) => {
671            for v in data.variants.iter() {
672                let last_at = v.fields.len().checked_sub(1).unwrap_or_default();
673                for (i, f) in v.fields.iter().enumerate() {
674                    let last = i == last_at;
675                    let ty = &f.ty;
676                    let tr = if last {
677                        quote!(::object_rainbow::ReflessObject)
678                    } else {
679                        quote!(::object_rainbow::ReflessInline)
680                    };
681                    if type_contains_generics(GContext { g, points: false }, ty) {
682                        generics.make_where_clause().predicates.push(
683                            parse_quote_spanned! { ty.span() =>
684                                #ty: #tr
685                            },
686                        );
687                    }
688                }
689            }
690        }
691        Data::Union(data) => {
692            return Err(Error::new_spanned(
693                data.union_token,
694                "`union`s are not supported",
695            ));
696        }
697    }
698    Ok(generics)
699}
700
701#[proc_macro_derive(ReflessInline)]
702pub fn derive_refless_inline(input: TokenStream) -> TokenStream {
703    let input = parse_macro_input!(input as DeriveInput);
704    let name = input.ident;
705    let generics = match bounds_refless_inline(input.generics, &input.data) {
706        Ok(g) => g,
707        Err(e) => return e.into_compile_error().into(),
708    };
709    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
710    let output = quote! {
711        #[automatically_derived]
712        impl #impl_generics ::object_rainbow::ReflessInline for #name #ty_generics #where_clause {}
713    };
714    TokenStream::from(output)
715}
716
717fn bounds_refless_inline(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
718    let g = &bounds_g(&generics);
719    match data {
720        Data::Struct(data) => {
721            for f in data.fields.iter() {
722                let ty = &f.ty;
723                if type_contains_generics(GContext { g, points: false }, ty) {
724                    generics.make_where_clause().predicates.push(
725                        parse_quote_spanned! { ty.span() =>
726                            #ty: ::object_rainbow::ReflessInline
727                        },
728                    );
729                }
730            }
731        }
732        Data::Enum(data) => {
733            for v in data.variants.iter() {
734                for f in v.fields.iter() {
735                    let ty = &f.ty;
736                    if type_contains_generics(GContext { g, points: false }, ty) {
737                        generics.make_where_clause().predicates.push(
738                            parse_quote_spanned! { ty.span() =>
739                                #ty: ::object_rainbow::ReflessInline
740                            },
741                        );
742                    }
743                }
744            }
745        }
746        Data::Union(data) => {
747            return Err(Error::new_spanned(
748                data.union_token,
749                "`union`s are not supported",
750            ));
751        }
752    }
753    Ok(generics)
754}
755
756#[proc_macro_derive(Size)]
757pub fn derive_size(input: TokenStream) -> TokenStream {
758    let input = parse_macro_input!(input as DeriveInput);
759    let name = input.ident;
760    let size_arr = gen_size_arr(&input.data);
761    let size = gen_size(&input.data);
762    let generics = match bounds_size(input.generics.clone(), &input.data, &size_arr) {
763        Ok(g) => g,
764        Err(e) => return e.into_compile_error().into(),
765    };
766    let (_, ty_generics, where_clause) = generics.split_for_impl();
767    let mut generics = input.generics;
768    generics.params.push(parse_quote!(
769        __Output: ::object_rainbow::typenum::Unsigned
770    ));
771    let (impl_generics, _, _) = generics.split_for_impl();
772    let output = quote! {
773        const _: () = {
774            use ::object_rainbow::typenum::tarr;
775
776            #[automatically_derived]
777            impl #impl_generics ::object_rainbow::Size for #name #ty_generics #where_clause {
778                const SIZE: usize = #size;
779
780                type Size = <#size_arr as ::object_rainbow::typenum::FoldAdd>::Output;
781            }
782        };
783    };
784    TokenStream::from(output)
785}
786
787fn bounds_size(
788    mut generics: Generics,
789    data: &Data,
790    size_arr: &proc_macro2::TokenStream,
791) -> syn::Result<Generics> {
792    let g = &bounds_g(&generics);
793    match data {
794        Data::Struct(data) => {
795            for f in data.fields.iter() {
796                let ty = &f.ty;
797                if type_contains_generics(GContext { g, points: false }, ty) {
798                    generics.make_where_clause().predicates.push(
799                        parse_quote_spanned! { ty.span() =>
800                            #ty: ::object_rainbow::Size
801                        },
802                    );
803                }
804            }
805        }
806        Data::Enum(data) => {
807            for v in data.variants.iter() {
808                for f in v.fields.iter() {
809                    let ty = &f.ty;
810                    if type_contains_generics(GContext { g, points: false }, ty) {
811                        generics.make_where_clause().predicates.push(
812                            parse_quote_spanned! { ty.span() =>
813                                #ty: ::object_rainbow::Size
814                            },
815                        );
816                    }
817                }
818            }
819            for v in data.variants.iter().skip(1) {
820                let arr = fields_size_arr(&v.fields, true);
821                generics.make_where_clause().predicates.push(parse_quote!(
822                    #arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
823                ));
824            }
825        }
826        Data::Union(data) => {
827            return Err(Error::new_spanned(
828                data.union_token,
829                "`union`s are not supported",
830            ));
831        }
832    }
833    generics.make_where_clause().predicates.push(parse_quote!(
834        #size_arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
835    ));
836    Ok(generics)
837}
838
839fn fields_size_arr(fields: &syn::Fields, as_enum: bool) -> proc_macro2::TokenStream {
840    let kind_size = quote! {
841        <
842            <
843                <
844                    Self
845                    as
846                    ::object_rainbow::Enum
847                >::Kind
848                as
849                ::object_rainbow::enumkind::EnumKind
850            >::Tag
851            as  ::object_rainbow::Size
852        >::Size
853    };
854    if fields.is_empty() {
855        return if as_enum {
856            quote! { tarr![#kind_size, ::object_rainbow::typenum::consts::U0] }
857        } else {
858            quote! { tarr![::object_rainbow::typenum::consts::U0] }
859        };
860    }
861    let size_arr = fields.iter().map(|f| {
862        let ty = &f.ty;
863        quote! { <#ty as ::object_rainbow::Size>::Size }
864    });
865    if as_enum {
866        quote! { tarr![#kind_size, #(#size_arr),*] }
867    } else {
868        quote! { tarr![#(#size_arr),*] }
869    }
870}
871
872fn gen_size_arr(data: &Data) -> proc_macro2::TokenStream {
873    match data {
874        Data::Struct(data) => fields_size_arr(&data.fields, false),
875        Data::Enum(data) => {
876            if let Some(v) = data.variants.first() {
877                fields_size_arr(&v.fields, true)
878            } else {
879                Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
880                    .into_compile_error()
881            }
882        }
883        Data::Union(data) => {
884            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
885        }
886    }
887}
888
889fn fields_size(fields: &syn::Fields) -> proc_macro2::TokenStream {
890    if fields.is_empty() {
891        return quote! {0};
892    }
893    let size = fields.iter().map(|f| {
894        let ty = &f.ty;
895        quote! { <#ty as ::object_rainbow::Size>::SIZE }
896    });
897    quote! {
898        #(#size)+*
899    }
900}
901
902fn gen_size(data: &Data) -> proc_macro2::TokenStream {
903    match data {
904        Data::Struct(data) => fields_size(&data.fields),
905        Data::Enum(data) => {
906            if let Some(v) = data.variants.first() {
907                let size = fields_size(&v.fields);
908                let kind_size = quote! {
909                    <
910                        <
911                            <
912                                Self
913                                as
914                                ::object_rainbow::Enum
915                            >::Kind
916                            as
917                            ::object_rainbow::enumkind::EnumKind
918                        >::Tag
919                        as  ::object_rainbow::Size
920                    >::SIZE
921                };
922                quote! { #kind_size + #size }
923            } else {
924                Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
925                    .into_compile_error()
926            }
927        }
928        Data::Union(data) => {
929            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
930        }
931    }
932}
933
934#[proc_macro_derive(Parse)]
935pub fn derive_parse(input: TokenStream) -> TokenStream {
936    let input = parse_macro_input!(input as DeriveInput);
937    let name = input.ident;
938    let generics = input.generics.clone();
939    let (_, ty_generics, _) = generics.split_for_impl();
940    let generics = match bounds_parse(input.generics, &input.data) {
941        Ok(g) => g,
942        Err(e) => return e.into_compile_error().into(),
943    };
944    let parse = gen_parse(&input.data);
945    let (impl_generics, _, where_clause) = generics.split_for_impl();
946    let output = quote! {
947        #[automatically_derived]
948        impl #impl_generics ::object_rainbow::Parse<__I> for #name #ty_generics #where_clause {
949            fn parse(mut input: __I) -> ::object_rainbow::Result<Self> {
950                #parse
951            }
952        }
953    };
954    TokenStream::from(output)
955}
956
957fn bounds_parse(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
958    match data {
959        Data::Struct(data) => {
960            let last_at = data.fields.len().checked_sub(1).unwrap_or_default();
961            for (i, f) in data.fields.iter().enumerate() {
962                let last = i == last_at;
963                let ty = &f.ty;
964                let tr = if last {
965                    quote!(::object_rainbow::Parse<__I>)
966                } else {
967                    quote!(::object_rainbow::ParseInline<__I>)
968                };
969                generics
970                    .make_where_clause()
971                    .predicates
972                    .push(parse_quote_spanned! { ty.span() =>
973                        #ty: #tr
974                    });
975            }
976        }
977        Data::Enum(data) => {
978            for v in data.variants.iter() {
979                let last_at = v.fields.len().checked_sub(1).unwrap_or_default();
980                for (i, f) in v.fields.iter().enumerate() {
981                    let last = i == last_at;
982                    let ty = &f.ty;
983                    let tr = if last {
984                        quote!(::object_rainbow::Parse<__I>)
985                    } else {
986                        quote!(::object_rainbow::ParseInline<__I>)
987                    };
988                    generics.make_where_clause().predicates.push(
989                        parse_quote_spanned! { ty.span() =>
990                            #ty: #tr
991                        },
992                    );
993                }
994            }
995        }
996        Data::Union(data) => {
997            return Err(Error::new_spanned(
998                data.union_token,
999                "`union`s are not supported",
1000            ));
1001        }
1002    }
1003    generics
1004        .params
1005        .push(parse_quote!(__I: ::object_rainbow::ParseInput));
1006    Ok(generics)
1007}
1008
1009fn gen_parse(data: &Data) -> proc_macro2::TokenStream {
1010    match data {
1011        Data::Struct(data) => {
1012            let arm = fields_parse(&data.fields);
1013            quote! { Ok(Self #arm)}
1014        }
1015        Data::Enum(data) => {
1016            let parse = data.variants.iter().map(|v| {
1017                let ident = &v.ident;
1018                let arm = fields_parse(&v.fields);
1019                quote! {
1020                    <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
1021                }
1022            });
1023            quote! {
1024                Ok(match input.parse_inline()? {
1025                    #(#parse)*
1026                })
1027            }
1028        }
1029        Data::Union(data) => {
1030            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1031        }
1032    }
1033}
1034
1035fn fields_parse(fields: &syn::Fields) -> proc_macro2::TokenStream {
1036    let last_at = fields.len().checked_sub(1).unwrap_or_default();
1037    match fields {
1038        syn::Fields::Named(fields) => {
1039            let parse = fields.named.iter().enumerate().map(|(i, f)| {
1040                let last = i == last_at;
1041                let i = f.ident.as_ref().unwrap();
1042                let method = if last {
1043                    quote!(parse)
1044                } else {
1045                    quote!(parse_inline)
1046                };
1047                quote_spanned! { f.ty.span() =>
1048                    #i: input.#method()?
1049                }
1050            });
1051            quote! { { #(#parse),* } }
1052        }
1053        syn::Fields::Unnamed(fields) => {
1054            let parse = fields.unnamed.iter().enumerate().map(|(i, f)| {
1055                let last = i == last_at;
1056                let method = if last {
1057                    quote!(parse)
1058                } else {
1059                    quote!(parse_inline)
1060                };
1061                quote_spanned! { f.ty.span() =>
1062                    input.#method()?
1063                }
1064            });
1065            quote! { (#(#parse),*) }
1066        }
1067        syn::Fields::Unit => quote! {},
1068    }
1069}
1070
1071#[proc_macro_derive(ParseInline)]
1072pub fn derive_parse_inline(input: TokenStream) -> TokenStream {
1073    let input = parse_macro_input!(input as DeriveInput);
1074    let name = input.ident;
1075    let generics = input.generics.clone();
1076    let (_, ty_generics, _) = generics.split_for_impl();
1077    let generics = match bounds_parse_inline(input.generics, &input.data) {
1078        Ok(g) => g,
1079        Err(e) => return e.into_compile_error().into(),
1080    };
1081    let parse_inline = gen_parse_inline(&input.data);
1082    let (impl_generics, _, where_clause) = generics.split_for_impl();
1083    let output = quote! {
1084        #[automatically_derived]
1085        impl #impl_generics ::object_rainbow::ParseInline<__I> for #name #ty_generics #where_clause {
1086            fn parse_inline(input: &mut __I) -> ::object_rainbow::Result<Self> {
1087                #parse_inline
1088            }
1089        }
1090    };
1091    TokenStream::from(output)
1092}
1093
1094fn bounds_parse_inline(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
1095    match data {
1096        Data::Struct(data) => {
1097            for f in data.fields.iter() {
1098                let ty = &f.ty;
1099                generics
1100                    .make_where_clause()
1101                    .predicates
1102                    .push(parse_quote_spanned! { ty.span() =>
1103                        #ty: ::object_rainbow::ParseInline<__I>
1104                    });
1105            }
1106        }
1107        Data::Enum(data) => {
1108            for v in data.variants.iter() {
1109                for f in v.fields.iter() {
1110                    let ty = &f.ty;
1111                    generics.make_where_clause().predicates.push(
1112                        parse_quote_spanned! { ty.span() =>
1113                            #ty: ::object_rainbow::ParseInline<__I>
1114                        },
1115                    );
1116                }
1117            }
1118        }
1119        Data::Union(data) => {
1120            return Err(Error::new_spanned(
1121                data.union_token,
1122                "`union`s are not supported",
1123            ));
1124        }
1125    }
1126    generics
1127        .params
1128        .push(parse_quote!(__I: ::object_rainbow::ParseInput));
1129    Ok(generics)
1130}
1131
1132fn fields_parse_inline(fields: &syn::Fields) -> proc_macro2::TokenStream {
1133    match fields {
1134        syn::Fields::Named(fields) => {
1135            let parse = fields.named.iter().map(|f| {
1136                let i = f.ident.as_ref().unwrap();
1137                quote_spanned! { f.ty.span() =>
1138                    #i: input.parse_inline()?
1139                }
1140            });
1141            quote! { { #(#parse),* } }
1142        }
1143        syn::Fields::Unnamed(fields) => {
1144            let parse = fields.unnamed.iter().map(|f| {
1145                quote_spanned! { f.ty.span() =>
1146                    input.parse_inline()?
1147                }
1148            });
1149            quote! { (#(#parse),*) }
1150        }
1151        syn::Fields::Unit => quote! {},
1152    }
1153}
1154
1155fn gen_parse_inline(data: &Data) -> proc_macro2::TokenStream {
1156    match data {
1157        Data::Struct(data) => {
1158            let arm = fields_parse_inline(&data.fields);
1159            quote! { Ok(Self #arm) }
1160        }
1161        Data::Enum(data) => {
1162            let parse_inline = data.variants.iter().map(|v| {
1163                let ident = &v.ident;
1164                let arm = fields_parse_inline(&v.fields);
1165                quote! {
1166                    <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
1167                }
1168            });
1169            quote! {
1170                Ok(match input.parse_inline()? {
1171                    #(#parse_inline)*
1172                })
1173            }
1174        }
1175        Data::Union(data) => {
1176            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1177        }
1178    }
1179}
1180
1181#[proc_macro_derive(ParseAsInline)]
1182pub fn derive_parse_as_inline(input: TokenStream) -> TokenStream {
1183    let input = parse_macro_input!(input as DeriveInput);
1184    let name = input.ident;
1185    let generics = input.generics.clone();
1186    let (_, ty_generics, _) = generics.split_for_impl();
1187    let generics = match bounds_parse_as_inline(input.generics, &name) {
1188        Ok(g) => g,
1189        Err(e) => return e.into_compile_error().into(),
1190    };
1191    let (impl_generics, _, where_clause) = generics.split_for_impl();
1192    let output = quote! {
1193        #[automatically_derived]
1194        impl #impl_generics ::object_rainbow::Parse<__I> for #name #ty_generics #where_clause {
1195            fn parse(input: __I) -> ::object_rainbow::Result<Self> {
1196                ::object_rainbow::ParseInline::<__I>::parse_as_inline(input)
1197            }
1198        }
1199    };
1200    TokenStream::from(output)
1201}
1202
1203fn bounds_parse_as_inline(mut generics: Generics, name: &Ident) -> syn::Result<Generics> {
1204    generics
1205        .make_where_clause()
1206        .predicates
1207        .push(parse_quote_spanned! { name.span() =>
1208            Self: ::object_rainbow::ParseInline::<__I>
1209        });
1210    generics
1211        .params
1212        .push(parse_quote!(__I: ::object_rainbow::ParseInput));
1213    Ok(generics)
1214}
1215
1216fn parse_path(attr: &Attribute) -> syn::Result<Type> {
1217    attr.parse_args::<LitStr>()?.parse()
1218}
1219
1220fn attr_str(attr: &Attribute) -> Option<String> {
1221    Some(attr.path().get_ident()?.to_string())
1222}
1223
1224#[proc_macro_derive(Enum, attributes(enumtag))]
1225pub fn derive_enum(input: TokenStream) -> TokenStream {
1226    let input = parse_macro_input!(input as DeriveInput);
1227    let name = input.ident;
1228    let generics = input.generics.clone();
1229    let (_, ty_generics, _) = generics.split_for_impl();
1230    let generics = input.generics;
1231    let variants = gen_variants(&input.data);
1232    let variant_count = gen_variant_count(&input.data);
1233    let to_tag = gen_to_tag(&input.data);
1234    let from_tag = gen_from_tag(&input.data);
1235    let kind = gen_kind(&input.data);
1236    let (impl_generics, _, where_clause) = generics.split_for_impl();
1237    let mut errors = Vec::new();
1238    let mut enumtag = None;
1239    for attr in &input.attrs {
1240        if attr_str(attr).as_deref() == Some("enumtag") {
1241            match parse_path(attr) {
1242                Ok(path) => {
1243                    if enumtag.is_some() {
1244                        errors.push(Error::new_spanned(path, "duplicate tag"));
1245                    } else {
1246                        enumtag = Some(path);
1247                    }
1248                }
1249                Err(e) => errors.push(e),
1250            }
1251        }
1252    }
1253    let enumtag = enumtag
1254        .unwrap_or_else(|| parse_quote!(::object_rainbow::numeric::Le<::core::num::NonZero<u8>>));
1255    let errors = errors.into_iter().map(|e| e.into_compile_error());
1256    let output = quote! {
1257        const _: () = {
1258            #(#errors)*
1259
1260            use ::object_rainbow::enumkind::EnumKind;
1261
1262            #[derive(Clone, Copy, ::object_rainbow::ParseAsInline)]
1263            pub enum __Kind {
1264                #variants
1265            }
1266
1267            #[automatically_derived]
1268            impl ::object_rainbow::enumkind::EnumKind for __Kind {
1269                type Tag = ::object_rainbow::enumkind::EnumTag<
1270                    #enumtag,
1271                    #variant_count,
1272                >;
1273
1274                fn to_tag(self) -> Self::Tag {
1275                    #to_tag
1276                }
1277
1278                fn from_tag(tag: Self::Tag) -> Self {
1279                    #from_tag
1280                }
1281            }
1282
1283            impl<I: ::object_rainbow::ParseInput> ::object_rainbow::ParseInline<I> for __Kind {
1284                fn parse_inline(input: &mut I) -> ::object_rainbow::Result<Self> {
1285                    Ok(::object_rainbow::enumkind::EnumKind::from_tag(input.parse_inline()?))
1286                }
1287            }
1288
1289            #[automatically_derived]
1290            impl #impl_generics ::object_rainbow::Enum for #name #ty_generics #where_clause {
1291                type Kind = __Kind;
1292
1293                fn kind(&self) -> Self::Kind {
1294                    #kind
1295                }
1296            }
1297        };
1298    };
1299    TokenStream::from(output)
1300}
1301
1302fn gen_variants(data: &Data) -> proc_macro2::TokenStream {
1303    match data {
1304        Data::Struct(data) => {
1305            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1306        }
1307        Data::Enum(data) => {
1308            let variants = data.variants.iter().map(|v| &v.ident);
1309            quote! { #(#variants),* }
1310        }
1311        Data::Union(data) => {
1312            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1313        }
1314    }
1315}
1316
1317fn gen_variant_count(data: &Data) -> proc_macro2::TokenStream {
1318    match data {
1319        Data::Struct(data) => {
1320            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1321        }
1322        Data::Enum(data) => {
1323            let variant_count = data.variants.len();
1324            quote! { #variant_count }
1325        }
1326        Data::Union(data) => {
1327            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1328        }
1329    }
1330}
1331
1332fn gen_to_tag(data: &Data) -> proc_macro2::TokenStream {
1333    match data {
1334        Data::Struct(data) => {
1335            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1336        }
1337        Data::Enum(data) => {
1338            let to_tag = data.variants.iter().enumerate().map(|(i, v)| {
1339                let ident = &v.ident;
1340                quote_spanned! { ident.span() =>
1341                    Self::#ident => ::object_rainbow::enumkind::EnumTag::from_const::<#i>(),
1342                }
1343            });
1344            quote! {
1345                match self {
1346                    #(#to_tag)*
1347                }
1348            }
1349        }
1350        Data::Union(data) => {
1351            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1352        }
1353    }
1354}
1355
1356fn gen_from_tag(data: &Data) -> proc_macro2::TokenStream {
1357    match data {
1358        Data::Struct(data) => {
1359            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1360        }
1361        Data::Enum(data) => {
1362            let from_tag = data.variants.iter().enumerate().map(|(i, v)| {
1363                let ident = &v.ident;
1364                quote_spanned! { ident.span() =>
1365                    #i => Self::#ident,
1366                }
1367            });
1368            quote! {
1369                match tag.to_usize() {
1370                    #(#from_tag)*
1371                    _ => unreachable!(),
1372                }
1373            }
1374        }
1375        Data::Union(data) => {
1376            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1377        }
1378    }
1379}
1380
1381fn gen_kind(data: &Data) -> proc_macro2::TokenStream {
1382    match data {
1383        Data::Struct(data) => {
1384            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1385        }
1386        Data::Enum(data) => {
1387            let variants = data.variants.iter().map(|v| {
1388                let ident = &v.ident;
1389                quote_spanned! { ident.span() =>
1390                    Self::#ident {..} => __Kind::#ident,
1391                }
1392            });
1393            quote! {
1394                match self {
1395                    #(#variants)*
1396                }
1397            }
1398        }
1399        Data::Union(data) => {
1400            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1401        }
1402    }
1403}
1404
1405#[proc_macro_derive(MaybeHasNiche)]
1406pub fn derive_maybe_has_niche(input: TokenStream) -> TokenStream {
1407    let input = parse_macro_input!(input as DeriveInput);
1408    let name = input.ident;
1409    let mn_array = gen_mn_array(&input.data);
1410    let (_, ty_generics, _) = input.generics.split_for_impl();
1411    let generics = match bounds_maybe_has_niche(input.generics.clone(), &input.data) {
1412        Ok(g) => g,
1413        Err(e) => return e.into_compile_error().into(),
1414    };
1415    let (impl_generics, _, where_clause) = generics.split_for_impl();
1416    let output = quote! {
1417        const _: () = {
1418            use ::object_rainbow::typenum::tarr;
1419
1420            #[automatically_derived]
1421            impl #impl_generics ::object_rainbow::MaybeHasNiche for #name #ty_generics #where_clause {
1422                type MnArray = #mn_array;
1423            }
1424        };
1425    };
1426    TokenStream::from(output)
1427}
1428
1429fn bounds_maybe_has_niche(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
1430    match data {
1431        Data::Struct(data) => {
1432            for f in data.fields.iter() {
1433                let ty = &f.ty;
1434                generics
1435                    .make_where_clause()
1436                    .predicates
1437                    .push(parse_quote_spanned! { ty.span() =>
1438                        #ty: ::object_rainbow::MaybeHasNiche<
1439                            MnArray: ::object_rainbow::MnArray<
1440                                MaybeNiche: ::object_rainbow::MaybeNiche
1441                            >
1442                        >
1443                    });
1444            }
1445        }
1446        Data::Enum(data) => {
1447            generics.params.push(parse_quote!(
1448                __N: ::object_rainbow::typenum::Unsigned
1449            ));
1450            for (i, v) in data.variants.iter().enumerate() {
1451                let mn_array = fields_mn_array(&v.fields, Some(i));
1452                generics
1453                    .make_where_clause()
1454                    .predicates
1455                    .push(parse_quote_spanned! { v.span() =>
1456                        #mn_array: ::object_rainbow::MnArray<
1457                            MaybeNiche: ::object_rainbow::NicheOr<N = __N>
1458                        >
1459                    });
1460                for f in v.fields.iter() {
1461                    let ty = &f.ty;
1462                    generics.make_where_clause().predicates.push(
1463                        parse_quote_spanned! { ty.span() =>
1464                            #ty: ::object_rainbow::MaybeHasNiche<
1465                                MnArray: ::object_rainbow::MnArray<
1466                                    MaybeNiche: ::object_rainbow::MaybeNiche
1467                                >
1468                            >
1469                        },
1470                    );
1471                }
1472            }
1473        }
1474        Data::Union(data) => {
1475            return Err(Error::new_spanned(
1476                data.union_token,
1477                "`union`s are not supported",
1478            ));
1479        }
1480    }
1481    Ok(generics)
1482}
1483
1484fn fields_mn_array(fields: &syn::Fields, variant: Option<usize>) -> proc_macro2::TokenStream {
1485    let mn_array = fields.iter().map(|f| {
1486        let ty = &f.ty;
1487        quote! {
1488            <
1489                <
1490                    #ty
1491                    as
1492                    ::object_rainbow::MaybeHasNiche
1493                >::MnArray
1494                as
1495                ::object_rainbow::MnArray
1496            >::MaybeNiche
1497        }
1498    });
1499    if let Some(variant) = variant {
1500        let kind_niche = quote! {
1501            ::object_rainbow::AutoEnumNiche<Self, #variant>
1502        };
1503        quote! { tarr![#kind_niche, ::object_rainbow::NoNiche<::object_rainbow::HackNiche<#variant>>, #(#mn_array),*] }
1504    } else {
1505        quote! { tarr![#(#mn_array),*] }
1506    }
1507}
1508
1509fn gen_mn_array(data: &Data) -> proc_macro2::TokenStream {
1510    match data {
1511        Data::Struct(data) => fields_mn_array(&data.fields, None),
1512        Data::Enum(data) => {
1513            let mn_array = data.variants.iter().enumerate().map(|(i, v)| {
1514                let mn_array = fields_mn_array(&v.fields, Some(i));
1515                quote! { <#mn_array as ::object_rainbow::MnArray>::MaybeNiche }
1516            });
1517            quote! {
1518                ::object_rainbow::NicheFoldOrArray<tarr![#(#mn_array),*]>
1519            }
1520        }
1521        Data::Union(data) => {
1522            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1523        }
1524    }
1525}