object_rainbow_derive/
lib.rs

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