object_rainbow_derive/
lib.rs

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