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            let last_at = data.fields.len().checked_sub(1).unwrap_or_default();
53            for (i, f) in data.fields.iter().enumerate() {
54                let last = i == last_at;
55                let ty = &f.ty;
56                let tr = if last {
57                    quote!(::object_rainbow::ToOutput)
58                } else {
59                    quote!(::object_rainbow::InlineOutput)
60                };
61                if !last || type_contains_generics(GContext { g, always: false }, ty) {
62                    generics.make_where_clause().predicates.push(
63                        parse_quote_spanned! { ty.span() =>
64                            #ty: #tr
65                        },
66                    );
67                }
68            }
69        }
70        Data::Enum(data) => {
71            for v in data.variants.iter() {
72                let last_at = v.fields.len().checked_sub(1).unwrap_or_default();
73                for (i, f) in v.fields.iter().enumerate() {
74                    let last = i == last_at;
75                    let ty = &f.ty;
76                    let tr = if last {
77                        quote!(::object_rainbow::ToOutput)
78                    } else {
79                        quote!(::object_rainbow::InlineOutput)
80                    };
81                    if !last || type_contains_generics(GContext { g, always: false }, ty) {
82                        generics.make_where_clause().predicates.push(
83                            parse_quote_spanned! { ty.span() =>
84                                #ty: #tr
85                            },
86                        );
87                    }
88                }
89            }
90        }
91        Data::Union(data) => {
92            return Err(Error::new_spanned(
93                data.union_token,
94                "`union`s are not supported",
95            ));
96        }
97    }
98    Ok(generics)
99}
100
101fn fields_to_output(fields: &syn::Fields) -> proc_macro2::TokenStream {
102    match fields {
103        syn::Fields::Named(fields) => {
104            let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
105            let to_output = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
106                quote_spanned! { f.ty.span() =>
107                    #i.to_output(output)
108                }
109            });
110            quote! {
111                { #(#let_self),* } => {
112                    #(#to_output);*
113                }
114            }
115        }
116        syn::Fields::Unnamed(fields) => {
117            let let_self = fields
118                .unnamed
119                .iter()
120                .enumerate()
121                .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
122            let to_output = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
123                quote_spanned! { f.ty.span() =>
124                    #i.to_output(output)
125                }
126            });
127            quote! {
128                (#(#let_self),*) => {
129                    #(#to_output);*
130                }
131            }
132        }
133        syn::Fields::Unit => quote! {
134            => {}
135        },
136    }
137}
138
139fn gen_to_output(data: &Data) -> proc_macro2::TokenStream {
140    match data {
141        Data::Struct(data) => {
142            let arm = fields_to_output(&data.fields);
143            quote! {
144                match self {
145                    Self #arm
146                }
147            }
148        }
149        Data::Enum(data) => {
150            let to_output = data.variants.iter().map(|v| {
151                let ident = &v.ident;
152                let arm = fields_to_output(&v.fields);
153                quote! { Self::#ident #arm }
154            });
155            quote! {
156                let kind = ::object_rainbow::Enum::kind(self);
157                let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
158                tag.to_output(output);
159                match self {
160                    #(#to_output)*
161                }
162            }
163        }
164        Data::Union(data) => {
165            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
166        }
167    }
168}
169
170#[proc_macro_derive(InlineOutput)]
171pub fn derive_inline_output(input: TokenStream) -> TokenStream {
172    let input = parse_macro_input!(input as DeriveInput);
173    let name = input.ident;
174    let generics = match bounds_inline_output(input.generics, &input.data) {
175        Ok(g) => g,
176        Err(e) => return e.into_compile_error().into(),
177    };
178    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
179    let output = quote! {
180        #[automatically_derived]
181        impl #impl_generics ::object_rainbow::InlineOutput for #name #ty_generics #where_clause {}
182    };
183    TokenStream::from(output)
184}
185
186fn bounds_inline_output(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
187    match data {
188        Data::Struct(data) => {
189            for f in data.fields.iter() {
190                let ty = &f.ty;
191                generics
192                    .make_where_clause()
193                    .predicates
194                    .push(parse_quote_spanned! { ty.span() =>
195                        #ty: ::object_rainbow::InlineOutput
196                    });
197            }
198        }
199        Data::Enum(data) => {
200            for v in data.variants.iter() {
201                for f in v.fields.iter() {
202                    let ty = &f.ty;
203                    generics.make_where_clause().predicates.push(
204                        parse_quote_spanned! { ty.span() =>
205                            #ty: ::object_rainbow::InlineOutput
206                        },
207                    );
208                }
209            }
210        }
211        Data::Union(data) => {
212            return Err(Error::new_spanned(
213                data.union_token,
214                "`union`s are not supported",
215            ));
216        }
217    }
218    Ok(generics)
219}
220
221#[proc_macro_derive(ListHashes, attributes(topology))]
222pub fn derive_list_hashes(input: TokenStream) -> TokenStream {
223    let input = parse_macro_input!(input as DeriveInput);
224    let name = input.ident;
225    let generics = input.generics.clone();
226    let (_, ty_generics, _) = generics.split_for_impl();
227    let generics = match bounds_list_hashes(input.generics, &input.data) {
228        Ok(g) => g,
229        Err(e) => return e.into_compile_error().into(),
230    };
231    let list_hashes = gen_list_hashes(&input.data);
232    let (impl_generics, _, where_clause) = generics.split_for_impl();
233    let output = quote! {
234        #[automatically_derived]
235        impl #impl_generics ::object_rainbow::ListHashes for #name #ty_generics #where_clause {
236            fn list_hashes(&self, visitor: &mut impl FnMut(::object_rainbow::Hash)) {
237                #list_hashes
238            }
239        }
240    };
241    TokenStream::from(output)
242}
243
244fn bounds_list_hashes(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
245    let g = &bounds_g(&generics);
246    match data {
247        Data::Struct(data) => {
248            for f in data.fields.iter() {
249                let ty = &f.ty;
250                if type_contains_generics(GContext { g, always: false }, ty) {
251                    generics.make_where_clause().predicates.push(
252                        parse_quote_spanned! { ty.span() =>
253                            #ty: ::object_rainbow::ListHashes
254                        },
255                    );
256                }
257            }
258        }
259        Data::Enum(data) => {
260            for v in data.variants.iter() {
261                for f in v.fields.iter() {
262                    let ty = &f.ty;
263                    if type_contains_generics(GContext { g, always: false }, ty) {
264                        generics.make_where_clause().predicates.push(
265                            parse_quote_spanned! { ty.span() =>
266                                #ty: ::object_rainbow::ListHashes
267                            },
268                        );
269                    }
270                }
271            }
272        }
273        Data::Union(data) => {
274            return Err(Error::new_spanned(
275                data.union_token,
276                "`union`s are not supported",
277            ));
278        }
279    }
280    Ok(generics)
281}
282
283fn fields_list_hashes(fields: &syn::Fields) -> proc_macro2::TokenStream {
284    match fields {
285        syn::Fields::Named(fields) => {
286            let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
287            let list_hashes = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
288                quote_spanned! { f.ty.span() =>
289                    #i.list_hashes(visitor)
290                }
291            });
292            quote! {
293                { #(#let_self),* } => {
294                    #(#list_hashes);*
295                }
296            }
297        }
298        syn::Fields::Unnamed(fields) => {
299            let let_self = fields
300                .unnamed
301                .iter()
302                .enumerate()
303                .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
304            let list_hashes = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
305                quote_spanned! { f.ty.span() =>
306                    #i.list_hashes(visitor)
307                }
308            });
309            quote! {
310                (#(#let_self),*) => {
311                    #(#list_hashes);*
312                }
313            }
314        }
315        syn::Fields::Unit => quote! {
316            => {}
317        },
318    }
319}
320
321fn gen_list_hashes(data: &Data) -> proc_macro2::TokenStream {
322    match data {
323        Data::Struct(data) => {
324            let arm = fields_list_hashes(&data.fields);
325            quote! {
326                match self {
327                    Self #arm
328                }
329            }
330        }
331        Data::Enum(data) => {
332            let to_output = data.variants.iter().map(|v| {
333                let ident = &v.ident;
334                let arm = fields_list_hashes(&v.fields);
335                quote! { Self::#ident #arm }
336            });
337            quote! {
338                let kind = ::object_rainbow::Enum::kind(self);
339                let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
340                tag.list_hashes(visitor);
341                match self {
342                    #(#to_output)*
343                }
344            }
345        }
346        Data::Union(data) => {
347            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
348        }
349    }
350}
351
352#[proc_macro_derive(Topological, attributes(topology))]
353pub fn derive_topological(input: TokenStream) -> TokenStream {
354    let input = parse_macro_input!(input as DeriveInput);
355    let name = input.ident;
356    let generics = input.generics.clone();
357    let (_, ty_generics, _) = generics.split_for_impl();
358    let mut errors = Vec::new();
359    let generics = match bounds_topological(
360        input.generics,
361        &input.data,
362        &input.attrs,
363        &mut errors,
364        &name,
365    ) {
366        Ok(g) => g,
367        Err(e) => return e.into_compile_error().into(),
368    };
369    let traverse = gen_traverse(&input.data);
370    let (impl_generics, _, where_clause) = generics.split_for_impl();
371    let errors = errors.into_iter().map(|e| e.into_compile_error());
372    let output = quote! {
373        #(#errors)*
374
375        #[automatically_derived]
376        impl #impl_generics ::object_rainbow::Topological for #name #ty_generics #where_clause {
377            fn traverse(&self, visitor: &mut impl ::object_rainbow::PointVisitor) {
378                #traverse
379            }
380        }
381    };
382    TokenStream::from(output)
383}
384
385struct TypeTopologyArgs {
386    recursive: bool,
387}
388
389impl Parse for TypeTopologyArgs {
390    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
391        let mut skip = false;
392        while !input.is_empty() {
393            let ident = input.parse::<Ident>()?;
394            if ident.to_string().as_str() != "recursive" {
395                return Err(Error::new(ident.span(), "expected: recursive"));
396            }
397            skip = true;
398            if !input.is_empty() {
399                input.parse::<Comma>()?;
400            }
401        }
402        Ok(Self { recursive: skip })
403    }
404}
405
406fn bounds_topological(
407    mut generics: Generics,
408    data: &Data,
409    attrs: &[Attribute],
410    errors: &mut Vec<Error>,
411    name: &Ident,
412) -> syn::Result<Generics> {
413    let mut recursive = false;
414    for attr in attrs {
415        if attr_str(attr).as_deref() == Some("topology") {
416            match attr.parse_args::<TypeTopologyArgs>() {
417                Ok(args) => recursive |= args.recursive,
418                Err(e) => errors.push(e),
419            }
420        }
421    }
422    let g = &bounds_g(&generics);
423    let bound = if recursive {
424        quote! { ::object_rainbow::Traversible }
425    } else {
426        quote! { ::object_rainbow::Topological }
427    };
428    match data {
429        Data::Struct(data) => {
430            for f in data.fields.iter() {
431                let ty = &f.ty;
432                if type_contains_generics(GContext { g, always: false }, ty) {
433                    generics.make_where_clause().predicates.push(
434                        parse_quote_spanned! { ty.span() =>
435                            #ty: #bound
436                        },
437                    );
438                }
439            }
440        }
441        Data::Enum(data) => {
442            for v in data.variants.iter() {
443                for f in v.fields.iter() {
444                    let ty = &f.ty;
445                    if type_contains_generics(GContext { g, always: false }, ty) {
446                        generics.make_where_clause().predicates.push(
447                            parse_quote_spanned! { ty.span() =>
448                                #ty: #bound
449                            },
450                        );
451                    }
452                }
453            }
454        }
455        Data::Union(data) => {
456            return Err(Error::new_spanned(
457                data.union_token,
458                "`union`s are not supported",
459            ));
460        }
461    }
462    if recursive {
463        generics
464            .make_where_clause()
465            .predicates
466            .push(parse_quote_spanned! { name.span() =>
467                Self: ToOutput
468            });
469    }
470    Ok(generics)
471}
472
473fn fields_traverse(fields: &syn::Fields) -> proc_macro2::TokenStream {
474    match fields {
475        syn::Fields::Named(fields) => {
476            let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
477            let traverse = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
478                quote_spanned! { f.ty.span() =>
479                    #i.traverse(visitor)
480                }
481            });
482            quote! {
483                { #(#let_self),* } => {
484                    #(#traverse);*
485                }
486            }
487        }
488        syn::Fields::Unnamed(fields) => {
489            let let_self = fields
490                .unnamed
491                .iter()
492                .enumerate()
493                .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
494            let traverse = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
495                quote_spanned! { f.ty.span() =>
496                    #i.traverse(visitor)
497                }
498            });
499            quote! {
500                (#(#let_self),*) => {
501                    #(#traverse);*
502                }
503            }
504        }
505        syn::Fields::Unit => quote! {
506            => {}
507        },
508    }
509}
510
511fn gen_traverse(data: &Data) -> proc_macro2::TokenStream {
512    match data {
513        Data::Struct(data) => {
514            let arm = fields_traverse(&data.fields);
515            quote! {
516                match self {
517                    Self #arm
518                }
519            }
520        }
521        Data::Enum(data) => {
522            let to_output = data.variants.iter().map(|v| {
523                let ident = &v.ident;
524                let arm = fields_traverse(&v.fields);
525                quote! { Self::#ident #arm }
526            });
527            quote! {
528                let kind = ::object_rainbow::Enum::kind(self);
529                let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
530                tag.traverse(visitor);
531                match self {
532                    #(#to_output)*
533                }
534            }
535        }
536        Data::Union(data) => {
537            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
538        }
539    }
540}
541
542#[proc_macro_derive(Tagged, attributes(tags))]
543pub fn derive_tagged(input: TokenStream) -> TokenStream {
544    let input = parse_macro_input!(input as DeriveInput);
545    let name = input.ident;
546    let mut errors = Vec::new();
547    let generics = match bounds_tagged(input.generics, &input.data, &mut errors) {
548        Ok(g) => g,
549        Err(e) => return e.into_compile_error().into(),
550    };
551    let tags = gen_tags(&input.data, &input.attrs, &mut errors);
552    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
553    let errors = errors.into_iter().map(|e| e.into_compile_error());
554    let output = quote! {
555        #(#errors)*
556
557        #[automatically_derived]
558        impl #impl_generics ::object_rainbow::Tagged for #name #ty_generics #where_clause {
559            const TAGS: ::object_rainbow::Tags = #tags;
560        }
561    };
562    TokenStream::from(output)
563}
564
565struct FieldTagArgs {
566    skip: bool,
567}
568
569impl Parse for FieldTagArgs {
570    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
571        let mut skip = false;
572        while !input.is_empty() {
573            let ident = input.parse::<Ident>()?;
574            if ident.to_string().as_str() != "skip" {
575                return Err(Error::new(ident.span(), "expected: skip"));
576            }
577            skip = true;
578            if !input.is_empty() {
579                input.parse::<Comma>()?;
580            }
581        }
582        Ok(Self { skip })
583    }
584}
585
586fn bounds_tagged(
587    mut generics: Generics,
588    data: &Data,
589    errors: &mut Vec<Error>,
590) -> syn::Result<Generics> {
591    let g = &bounds_g(&generics);
592    match data {
593        Data::Struct(data) => {
594            for f in data.fields.iter() {
595                let mut skip = false;
596                for attr in &f.attrs {
597                    if attr_str(attr).as_deref() == Some("tags") {
598                        match attr.parse_args::<FieldTagArgs>() {
599                            Ok(args) => skip |= args.skip,
600                            Err(e) => errors.push(e),
601                        }
602                    }
603                }
604                if !skip {
605                    let ty = &f.ty;
606                    if type_contains_generics(GContext { g, always: false }, ty) {
607                        generics.make_where_clause().predicates.push(
608                            parse_quote_spanned! { ty.span() =>
609                                #ty: ::object_rainbow::Tagged
610                            },
611                        );
612                    }
613                }
614            }
615        }
616        Data::Enum(data) => {
617            for v in data.variants.iter() {
618                for f in v.fields.iter() {
619                    let mut skip = false;
620                    for attr in &f.attrs {
621                        if attr_str(attr).as_deref() == Some("tags") {
622                            match attr.parse_args::<FieldTagArgs>() {
623                                Ok(args) => skip |= args.skip,
624                                Err(e) => errors.push(e),
625                            }
626                        }
627                    }
628                    if !skip {
629                        let ty = &f.ty;
630                        if type_contains_generics(GContext { g, always: false }, ty) {
631                            generics.make_where_clause().predicates.push(
632                                parse_quote_spanned! { ty.span() =>
633                                    #ty: ::object_rainbow::Tagged
634                                },
635                            );
636                        }
637                    }
638                }
639            }
640        }
641        Data::Union(data) => {
642            return Err(Error::new_spanned(
643                data.union_token,
644                "`union`s are not supported",
645            ));
646        }
647    }
648    Ok(generics)
649}
650
651struct StructTagArgs {
652    tags: Vec<LitStr>,
653}
654
655impl Parse for StructTagArgs {
656    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
657        let mut tags = Vec::new();
658        while !input.is_empty() {
659            let tag = input.parse::<LitStr>()?;
660            tags.push(tag);
661            if !input.is_empty() {
662                input.parse::<Comma>()?;
663            }
664        }
665        Ok(Self { tags })
666    }
667}
668
669fn fields_tags(fields: &syn::Fields) -> Vec<proc_macro2::TokenStream> {
670    fields
671        .iter()
672        .filter_map(|f| {
673            let mut skip = false;
674            for attr in &f.attrs {
675                if attr_str(attr).as_deref() == Some("tags") {
676                    skip |= attr.parse_args::<FieldTagArgs>().ok()?.skip;
677                }
678            }
679            let ty = &f.ty;
680            (!skip).then_some(quote! { <#ty as ::object_rainbow::Tagged>::TAGS })
681        })
682        .collect()
683}
684
685fn gen_tags(data: &Data, attrs: &[Attribute], errors: &mut Vec<Error>) -> proc_macro2::TokenStream {
686    match data {
687        Data::Struct(data) => {
688            let mut tags = Vec::new();
689            for attr in attrs {
690                if attr_str(attr).as_deref() == Some("tags") {
691                    match attr.parse_args::<StructTagArgs>() {
692                        Ok(mut args) => tags.append(&mut args.tags),
693                        Err(e) => errors.push(e),
694                    }
695                }
696            }
697            let nested = fields_tags(&data.fields);
698            if nested.len() == 1 && tags.is_empty() {
699                let nested = nested.into_iter().next().unwrap();
700                quote! {
701                    #nested
702                }
703            } else {
704                quote! {
705                    ::object_rainbow::Tags(&[#(#tags),*], &[#(&#nested),*])
706                }
707            }
708        }
709        Data::Enum(data) => {
710            let mut tags = Vec::new();
711            for attr in attrs {
712                if attr_str(attr).as_deref() == Some("tags") {
713                    match attr.parse_args::<StructTagArgs>() {
714                        Ok(mut args) => tags.append(&mut args.tags),
715                        Err(e) => errors.push(e),
716                    }
717                }
718            }
719            let mut nested: Vec<_> = data
720                .variants
721                .iter()
722                .flat_map(|v| fields_tags(&v.fields))
723                .collect();
724            let kind_tags = quote! {
725                <
726                    <
727                        <
728                            Self
729                            as
730                            ::object_rainbow::Enum
731                        >::Kind
732                        as
733                        ::object_rainbow::enumkind::EnumKind
734                    >::Tag
735                    as  ::object_rainbow::Tagged
736                >::TAGS
737            };
738            nested.insert(0, kind_tags);
739            if nested.len() == 1 && tags.is_empty() {
740                let nested = nested.into_iter().next().unwrap();
741                quote! {
742                    #nested
743                }
744            } else {
745                quote! {
746                    ::object_rainbow::Tags(&[#(#tags),*], &[#(&#nested),*])
747                }
748            }
749        }
750        Data::Union(data) => {
751            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
752        }
753    }
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, always: 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, always: 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}