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