Skip to main content

object_rainbow_derive/
lib.rs

1//! `#[derive(...)]`s for [`object-rainbow`](<https://docs.rs/object-rainbow>).
2
3use std::collections::BTreeSet;
4
5use darling::FromMeta;
6use proc_macro::TokenStream;
7use quote::{ToTokens, quote, quote_spanned};
8use syn::{
9    Attribute, Data, DeriveInput, Error, Expr, FnArg, GenericParam, Generics, Ident, ImplItem,
10    ItemTrait, LitStr, Path, TraitItem, Type, WherePredicate, parse::Parse, parse_macro_input,
11    parse_quote, parse_quote_spanned, spanned::Spanned, token::Comma,
12};
13
14use self::contains_generics::{GContext, type_contains_generics};
15
16mod contains_generics;
17
18fn bounds_g(generics: &Generics) -> BTreeSet<Ident> {
19    generics
20        .params
21        .iter()
22        .filter_map(|param| match param {
23            GenericParam::Lifetime(_) => None,
24            GenericParam::Type(param) => Some(&param.ident),
25            GenericParam::Const(param) => Some(&param.ident),
26        })
27        .cloned()
28        .collect()
29}
30
31#[derive(Debug, FromMeta)]
32#[darling(derive_syn_parse)]
33struct RainbowArgs {
34    #[darling(default)]
35    remote: Option<Type>,
36}
37
38fn parse_for(name: &Ident, attrs: &[Attribute]) -> proc_macro2::TokenStream {
39    for attr in attrs {
40        if attr_str(attr).as_deref() == Some("rainbow") {
41            match attr.parse_args::<RainbowArgs>() {
42                Ok(RainbowArgs { remote }) => {
43                    if let Some(remote) = remote {
44                        return remote.to_token_stream();
45                    }
46                }
47                Err(e) => return e.into_compile_error(),
48            }
49        }
50    }
51    name.to_token_stream()
52}
53
54/// ```rust
55/// use object_rainbow::{InlineOutput, ToOutput};
56///
57/// #[derive(ToOutput)]
58/// struct Three<A, B, C> {
59///     a: A,
60///     b: B,
61///     c: C,
62/// }
63///
64/// object_rainbow::assert_impl!(
65///     impl<A, B, C> ToOutput for Three<A, B, C>
66///     where
67///         A: InlineOutput,
68///         B: InlineOutput,
69///         C: ToOutput,
70///     {}
71/// );
72/// ```
73#[proc_macro_derive(ToOutput, attributes(rainbow))]
74pub fn derive_to_output(input: TokenStream) -> TokenStream {
75    let input = parse_macro_input!(input as DeriveInput);
76    let name = input.ident;
77    let generics = match bounds_to_output(input.generics, &input.data) {
78        Ok(g) => g,
79        Err(e) => return e.into_compile_error().into(),
80    };
81    let to_output = gen_to_output(&input.data);
82    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
83    let target = parse_for(&name, &input.attrs);
84    let output = quote! {
85        #[automatically_derived]
86        impl #impl_generics ::object_rainbow::ToOutput for #target #ty_generics #where_clause {
87            fn to_output(&self, output: &mut impl ::object_rainbow::Output) {
88                #to_output
89            }
90        }
91    };
92    TokenStream::from(output)
93}
94
95fn bounds_to_output(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
96    let g = &bounds_g(&generics);
97    match data {
98        Data::Struct(data) => {
99            let last_at = data.fields.len().saturating_sub(1);
100            for (i, f) in data.fields.iter().enumerate() {
101                let last = i == last_at;
102                let ty = &f.ty;
103                let tr = if last {
104                    quote!(::object_rainbow::ToOutput)
105                } else {
106                    quote!(::object_rainbow::InlineOutput)
107                };
108                if !last || type_contains_generics(GContext { g, always: false }, ty) {
109                    generics.make_where_clause().predicates.push(
110                        parse_quote_spanned! { ty.span() =>
111                            #ty: #tr
112                        },
113                    );
114                }
115            }
116        }
117        Data::Enum(data) => {
118            for v in data.variants.iter() {
119                let last_at = v.fields.len().saturating_sub(1);
120                for (i, f) in v.fields.iter().enumerate() {
121                    let last = i == last_at;
122                    let ty = &f.ty;
123                    let tr = if last {
124                        quote!(::object_rainbow::ToOutput)
125                    } else {
126                        quote!(::object_rainbow::InlineOutput)
127                    };
128                    if !last || type_contains_generics(GContext { g, always: false }, ty) {
129                        generics.make_where_clause().predicates.push(
130                            parse_quote_spanned! { ty.span() =>
131                                #ty: #tr
132                            },
133                        );
134                    }
135                }
136            }
137        }
138        Data::Union(data) => {
139            return Err(Error::new_spanned(
140                data.union_token,
141                "`union`s are not supported",
142            ));
143        }
144    }
145    Ok(generics)
146}
147
148fn fields_to_output(fields: &syn::Fields) -> proc_macro2::TokenStream {
149    match fields {
150        syn::Fields::Named(fields) => {
151            let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
152            let to_output = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
153                quote_spanned! { f.ty.span() =>
154                    #i.to_output(output)
155                }
156            });
157            quote! {
158                { #(#let_self),* } => {
159                    #(#to_output);*
160                }
161            }
162        }
163        syn::Fields::Unnamed(fields) => {
164            let let_self = fields
165                .unnamed
166                .iter()
167                .enumerate()
168                .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
169            let to_output = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
170                quote_spanned! { f.ty.span() =>
171                    #i.to_output(output)
172                }
173            });
174            quote! {
175                (#(#let_self),*) => {
176                    #(#to_output);*
177                }
178            }
179        }
180        syn::Fields::Unit => quote! {
181            => {}
182        },
183    }
184}
185
186fn gen_to_output(data: &Data) -> proc_macro2::TokenStream {
187    match data {
188        Data::Struct(data) => {
189            let arm = fields_to_output(&data.fields);
190            quote! {
191                match self {
192                    Self #arm
193                }
194            }
195        }
196        Data::Enum(data) => {
197            let to_output = data.variants.iter().map(|v| {
198                let ident = &v.ident;
199                let arm = fields_to_output(&v.fields);
200                quote! { Self::#ident #arm }
201            });
202            quote! {
203                let kind = ::object_rainbow::Enum::kind(self);
204                let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
205                tag.to_output(output);
206                match self {
207                    #(#to_output)*
208                }
209            }
210        }
211        Data::Union(data) => {
212            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
213        }
214    }
215}
216
217/// ```rust
218/// use object_rainbow::{InlineOutput, ToOutput};
219///
220/// #[derive(ToOutput, InlineOutput)]
221/// struct Three<A, B, C> {
222///     a: A,
223///     b: B,
224///     c: C,
225/// }
226///
227/// object_rainbow::assert_impl!(
228///     impl<A, B, C> InlineOutput for Three<A, B, C>
229///     where
230///         A: InlineOutput,
231///         B: InlineOutput,
232///         C: InlineOutput,
233///     {}
234/// );
235/// ```
236#[proc_macro_derive(InlineOutput)]
237pub fn derive_inline_output(input: TokenStream) -> TokenStream {
238    let input = parse_macro_input!(input as DeriveInput);
239    let name = input.ident;
240    let generics = match bounds_inline_output(input.generics, &input.data) {
241        Ok(g) => g,
242        Err(e) => return e.into_compile_error().into(),
243    };
244    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
245    let target = parse_for(&name, &input.attrs);
246    let output = quote! {
247        #[automatically_derived]
248        impl #impl_generics ::object_rainbow::InlineOutput for #target #ty_generics #where_clause {}
249    };
250    TokenStream::from(output)
251}
252
253fn bounds_inline_output(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
254    match data {
255        Data::Struct(data) => {
256            for f in data.fields.iter() {
257                let ty = &f.ty;
258                generics
259                    .make_where_clause()
260                    .predicates
261                    .push(parse_quote_spanned! { ty.span() =>
262                        #ty: ::object_rainbow::InlineOutput
263                    });
264            }
265        }
266        Data::Enum(data) => {
267            for v in data.variants.iter() {
268                for f in v.fields.iter() {
269                    let ty = &f.ty;
270                    generics.make_where_clause().predicates.push(
271                        parse_quote_spanned! { ty.span() =>
272                            #ty: ::object_rainbow::InlineOutput
273                        },
274                    );
275                }
276            }
277        }
278        Data::Union(data) => {
279            return Err(Error::new_spanned(
280                data.union_token,
281                "`union`s are not supported",
282            ));
283        }
284    }
285    Ok(generics)
286}
287
288/// ```rust
289/// use object_rainbow::ListHashes;
290///
291/// #[derive(ListHashes)]
292/// struct Three<A, B, C> {
293///     a: A,
294///     b: B,
295///     c: C,
296/// }
297///
298/// object_rainbow::assert_impl!(
299///     impl<A, B, C> ListHashes for Three<A, B, C>
300///     where
301///         A: ListHashes,
302///         B: ListHashes,
303///         C: ListHashes,
304///     {}
305/// );
306/// ```
307#[proc_macro_derive(ListHashes, attributes(topology))]
308pub fn derive_list_hashes(input: TokenStream) -> TokenStream {
309    let input = parse_macro_input!(input as DeriveInput);
310    let name = input.ident;
311    let generics = input.generics.clone();
312    let (_, ty_generics, _) = generics.split_for_impl();
313    let generics = match bounds_list_hashes(input.generics, &input.data) {
314        Ok(g) => g,
315        Err(e) => return e.into_compile_error().into(),
316    };
317    let list_hashes = gen_list_hashes(&input.data);
318    let (impl_generics, _, where_clause) = generics.split_for_impl();
319    let target = parse_for(&name, &input.attrs);
320    let output = quote! {
321        #[automatically_derived]
322        impl #impl_generics ::object_rainbow::ListHashes for #target #ty_generics #where_clause {
323            fn list_hashes(&self, visitor: &mut impl FnMut(::object_rainbow::Hash)) {
324                #list_hashes
325            }
326        }
327    };
328    TokenStream::from(output)
329}
330
331fn bounds_list_hashes(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
332    let g = &bounds_g(&generics);
333    match data {
334        Data::Struct(data) => {
335            for f in data.fields.iter() {
336                let ty = &f.ty;
337                if type_contains_generics(GContext { g, always: false }, ty) {
338                    generics.make_where_clause().predicates.push(
339                        parse_quote_spanned! { ty.span() =>
340                            #ty: ::object_rainbow::ListHashes
341                        },
342                    );
343                }
344            }
345        }
346        Data::Enum(data) => {
347            for v in data.variants.iter() {
348                for f in v.fields.iter() {
349                    let ty = &f.ty;
350                    if type_contains_generics(GContext { g, always: false }, ty) {
351                        generics.make_where_clause().predicates.push(
352                            parse_quote_spanned! { ty.span() =>
353                                #ty: ::object_rainbow::ListHashes
354                            },
355                        );
356                    }
357                }
358            }
359        }
360        Data::Union(data) => {
361            return Err(Error::new_spanned(
362                data.union_token,
363                "`union`s are not supported",
364            ));
365        }
366    }
367    Ok(generics)
368}
369
370fn fields_list_hashes(fields: &syn::Fields) -> proc_macro2::TokenStream {
371    match fields {
372        syn::Fields::Named(fields) => {
373            let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
374            let list_hashes = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
375                quote_spanned! { f.ty.span() =>
376                    #i.list_hashes(visitor)
377                }
378            });
379            quote! {
380                { #(#let_self),* } => {
381                    #(#list_hashes);*
382                }
383            }
384        }
385        syn::Fields::Unnamed(fields) => {
386            let let_self = fields
387                .unnamed
388                .iter()
389                .enumerate()
390                .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
391            let list_hashes = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
392                quote_spanned! { f.ty.span() =>
393                    #i.list_hashes(visitor)
394                }
395            });
396            quote! {
397                (#(#let_self),*) => {
398                    #(#list_hashes);*
399                }
400            }
401        }
402        syn::Fields::Unit => quote! {
403            => {}
404        },
405    }
406}
407
408fn gen_list_hashes(data: &Data) -> proc_macro2::TokenStream {
409    match data {
410        Data::Struct(data) => {
411            let arm = fields_list_hashes(&data.fields);
412            quote! {
413                match self {
414                    Self #arm
415                }
416            }
417        }
418        Data::Enum(data) => {
419            let to_output = data.variants.iter().map(|v| {
420                let ident = &v.ident;
421                let arm = fields_list_hashes(&v.fields);
422                quote! { Self::#ident #arm }
423            });
424            quote! {
425                let kind = ::object_rainbow::Enum::kind(self);
426                let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
427                tag.list_hashes(visitor);
428                match self {
429                    #(#to_output)*
430                }
431            }
432        }
433        Data::Union(data) => {
434            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
435        }
436    }
437}
438
439/// ```rust
440/// use object_rainbow::{ListHashes, Topological};
441///
442/// #[derive(ListHashes, Topological)]
443/// struct Three<A, B, C> {
444///     a: A,
445///     b: B,
446///     c: C,
447/// }
448///
449/// object_rainbow::assert_impl!(
450///     impl<A, B, C> Topological for Three<A, B, C>
451///     where
452///         A: Topological,
453///         B: Topological,
454///         C: Topological,
455///     {}
456/// );
457/// ```
458#[proc_macro_derive(Topological, attributes(topology))]
459pub fn derive_topological(input: TokenStream) -> TokenStream {
460    let input = parse_macro_input!(input as DeriveInput);
461    let name = input.ident;
462    let generics = input.generics.clone();
463    let (_, ty_generics, _) = generics.split_for_impl();
464    let generics = match bounds_topological(input.generics, &input.data, &input.attrs, &name) {
465        Ok(g) => g,
466        Err(e) => return e.into_compile_error().into(),
467    };
468    let traverse = gen_traverse(&input.data);
469    let (impl_generics, _, where_clause) = generics.split_for_impl();
470    let target = parse_for(&name, &input.attrs);
471    let output = quote! {
472        const _: () = {
473            #[automatically_derived]
474            impl #impl_generics ::object_rainbow::Topological for #target #ty_generics
475            #where_clause
476            {
477                fn traverse(&self, visitor: &mut impl ::object_rainbow::PointVisitor) {
478                    #traverse
479                }
480            }
481        };
482    };
483    TokenStream::from(output)
484}
485
486#[derive(Debug, FromMeta)]
487#[darling(derive_syn_parse)]
488struct ContainerTopologyArgs {
489    #[darling(default)]
490    recursive: bool,
491    #[darling(default)]
492    inline: bool,
493    #[darling(default)]
494    unchecked: bool,
495    #[darling(default)]
496    bound: Option<LitStr>,
497}
498
499fn parse_recursive_inline(
500    attrs: &[Attribute],
501) -> syn::Result<(bool, bool, bool, Vec<WherePredicate>)> {
502    let mut r = false;
503    let mut i = false;
504    let mut u = false;
505    let mut wheres = Vec::new();
506    for attr in attrs {
507        if attr_str(attr).as_deref() == Some("topology") {
508            let ContainerTopologyArgs {
509                recursive,
510                inline,
511                unchecked,
512                bound,
513            } = attr.parse_args()?;
514            if recursive {
515                r = true;
516            }
517            if inline {
518                i = true;
519            }
520            if unchecked {
521                u = true;
522            }
523            if let Some(bound) = bound {
524                wheres.push(bound.parse()?);
525            }
526        }
527    }
528    Ok((r, i, u, wheres))
529}
530
531#[derive(Debug, FromMeta)]
532#[darling(derive_syn_parse)]
533struct FieldTopologyArgs {
534    bound: Option<Path>,
535    #[darling(default)]
536    unchecked: bool,
537    with: Option<Expr>,
538}
539
540fn bounds_topological(
541    mut generics: Generics,
542    data: &Data,
543    attrs: &[Attribute],
544    name: &Ident,
545) -> syn::Result<Generics> {
546    let (recursive, inline, u, wheres) = parse_recursive_inline(attrs)?;
547    let g = &bounds_g(&generics);
548    let bound = if recursive {
549        quote! { ::object_rainbow::Traversible }
550    } else {
551        quote! { ::object_rainbow::Topological }
552    };
553    match data {
554        Data::Struct(data) => {
555            'field: for f in data.fields.iter() {
556                let ty = &f.ty;
557                let mut b = None;
558                for attr in &f.attrs {
559                    if attr_str(attr).as_deref() == Some("topology") {
560                        let FieldTopologyArgs {
561                            bound, unchecked, ..
562                        } = attr.parse_args()?;
563                        if unchecked {
564                            continue 'field;
565                        }
566                        if let Some(bound) = bound {
567                            b = Some(bound);
568                        }
569                    }
570                }
571                let bound = if let Some(bound) = b {
572                    quote! { #bound }
573                } else {
574                    if u {
575                        continue 'field;
576                    }
577                    bound.clone()
578                };
579                if type_contains_generics(GContext { g, always: false }, ty) {
580                    generics.make_where_clause().predicates.push(
581                        parse_quote_spanned! { ty.span() =>
582                            #ty: #bound
583                        },
584                    );
585                }
586            }
587        }
588        Data::Enum(data) => {
589            for v in data.variants.iter() {
590                'field: for f in v.fields.iter() {
591                    let ty = &f.ty;
592                    let mut b = None;
593                    for attr in &f.attrs {
594                        if attr_str(attr).as_deref() == Some("topology") {
595                            let FieldTopologyArgs {
596                                bound, unchecked, ..
597                            } = attr.parse_args()?;
598                            if unchecked {
599                                continue 'field;
600                            }
601                            if let Some(bound) = bound {
602                                b = Some(bound);
603                            }
604                        }
605                    }
606                    let bound = if let Some(bound) = b {
607                        quote! { #bound }
608                    } else {
609                        if u {
610                            continue 'field;
611                        }
612                        bound.clone()
613                    };
614                    if type_contains_generics(GContext { g, always: false }, ty) {
615                        generics.make_where_clause().predicates.push(
616                            parse_quote_spanned! { ty.span() =>
617                                #ty: #bound
618                            },
619                        );
620                    }
621                }
622            }
623        }
624        Data::Union(data) => {
625            return Err(Error::new_spanned(
626                data.union_token,
627                "`union`s are not supported",
628            ));
629        }
630    }
631    let output_bound = if inline {
632        quote! {
633            ::object_rainbow::InlineOutput
634        }
635    } else {
636        quote! {
637            ::object_rainbow::ToOutput
638        }
639    };
640    if recursive {
641        generics
642            .make_where_clause()
643            .predicates
644            .push(parse_quote_spanned! { name.span() =>
645                Self: #output_bound + ::object_rainbow::Tagged
646            });
647    }
648    for bound in wheres {
649        generics.make_where_clause().predicates.push(bound);
650    }
651    Ok(generics)
652}
653
654fn fields_traverse(fields: &syn::Fields) -> proc_macro2::TokenStream {
655    match fields {
656        syn::Fields::Named(fields) => {
657            let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
658            let traverse = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
659                let ty = &f.ty;
660                let mut w = None;
661                let mut b = None;
662                for attr in &f.attrs {
663                    if attr_str(attr).as_deref() == Some("topology") {
664                        let FieldTopologyArgs { with, bound, .. } = match attr.parse_args() {
665                            Ok(args) => args,
666                            Err(e) => return e.into_compile_error(),
667                        };
668                        if let Some(with) = with {
669                            w = Some(with);
670                        }
671                        if let Some(bound) = bound {
672                            b = Some(bound);
673                        }
674                    }
675                }
676                if let Some(with) = w {
677                    if let Some(bound) = b {
678                        quote_spanned! { f.ty.span() =>
679                            <#ty as #bound>::#with(#i, visitor)
680                        }
681                    } else {
682                        quote_spanned! { f.ty.span() =>
683                            #with(#i, visitor)
684                        }
685                    }
686                } else {
687                    quote_spanned! { f.ty.span() =>
688                        #i.traverse(visitor)
689                    }
690                }
691            });
692            quote! {
693                { #(#let_self),* } => {
694                    #(#traverse);*
695                }
696            }
697        }
698        syn::Fields::Unnamed(fields) => {
699            let let_self = fields
700                .unnamed
701                .iter()
702                .enumerate()
703                .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
704            let traverse = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
705                let ty = &f.ty;
706                let mut w = None;
707                let mut b = None;
708                for attr in &f.attrs {
709                    if attr_str(attr).as_deref() == Some("topology") {
710                        let FieldTopologyArgs { with, bound, .. } = match attr.parse_args() {
711                            Ok(args) => args,
712                            Err(e) => return e.into_compile_error(),
713                        };
714                        if let Some(with) = with {
715                            w = Some(with);
716                        }
717                        if let Some(bound) = bound {
718                            b = Some(bound);
719                        }
720                    }
721                }
722                if let Some(with) = w {
723                    if let Some(bound) = b {
724                        quote_spanned! { f.ty.span() =>
725                            <#ty as #bound>::#with(#i, visitor)
726                        }
727                    } else {
728                        quote_spanned! { f.ty.span() =>
729                            #with(#i, visitor)
730                        }
731                    }
732                } else {
733                    quote_spanned! { f.ty.span() =>
734                        #i.traverse(visitor)
735                    }
736                }
737            });
738            quote! {
739                (#(#let_self),*) => {
740                    #(#traverse);*
741                }
742            }
743        }
744        syn::Fields::Unit => quote! {
745            => {}
746        },
747    }
748}
749
750fn gen_traverse(data: &Data) -> proc_macro2::TokenStream {
751    match data {
752        Data::Struct(data) => {
753            let arm = fields_traverse(&data.fields);
754            quote! {
755                match self {
756                    Self #arm
757                }
758            }
759        }
760        Data::Enum(data) => {
761            let to_output = data.variants.iter().map(|v| {
762                let ident = &v.ident;
763                let arm = fields_traverse(&v.fields);
764                quote! { Self::#ident #arm }
765            });
766            quote! {
767                let kind = ::object_rainbow::Enum::kind(self);
768                let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
769                tag.traverse(visitor);
770                match self {
771                    #(#to_output)*
772                }
773            }
774        }
775        Data::Union(data) => {
776            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
777        }
778    }
779}
780
781/// ```rust
782/// use object_rainbow::Tagged;
783///
784/// #[derive(Tagged)]
785/// struct Three<A, B, C> {
786///     a: A,
787///     #[tags(skip)]
788///     b: B,
789///     c: C,
790/// }
791///
792/// object_rainbow::assert_impl!(
793///     impl<A, B, C> Tagged for Three<A, B, C>
794///     where
795///         A: Tagged,
796///         C: Tagged,
797///     {}
798/// );
799/// ```
800#[proc_macro_derive(Tagged, attributes(tags))]
801pub fn derive_tagged(input: TokenStream) -> TokenStream {
802    let input = parse_macro_input!(input as DeriveInput);
803    let name = input.ident;
804    let mut errors = Vec::new();
805    let generics = match bounds_tagged(input.generics, &input.data, &mut errors) {
806        Ok(g) => g,
807        Err(e) => return e.into_compile_error().into(),
808    };
809    let tags = gen_tags(&input.data, &input.attrs, &mut errors);
810    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
811    let errors = errors.into_iter().map(|e| e.into_compile_error());
812    let target = parse_for(&name, &input.attrs);
813    let output = quote! {
814        #(#errors)*
815
816        #[automatically_derived]
817        impl #impl_generics ::object_rainbow::Tagged for #target #ty_generics #where_clause {
818            const TAGS: ::object_rainbow::Tags = #tags;
819        }
820    };
821    TokenStream::from(output)
822}
823
824struct FieldTagArgs {
825    skip: bool,
826}
827
828impl Parse for FieldTagArgs {
829    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
830        let mut skip = false;
831        while !input.is_empty() {
832            let ident = input.parse::<Ident>()?;
833            if ident.to_string().as_str() != "skip" {
834                return Err(Error::new(ident.span(), "expected: skip"));
835            }
836            skip = true;
837            if !input.is_empty() {
838                input.parse::<Comma>()?;
839            }
840        }
841        Ok(Self { skip })
842    }
843}
844
845fn bounds_tagged(
846    mut generics: Generics,
847    data: &Data,
848    errors: &mut Vec<Error>,
849) -> syn::Result<Generics> {
850    let g = &bounds_g(&generics);
851    match data {
852        Data::Struct(data) => {
853            for f in data.fields.iter() {
854                let mut skip = false;
855                for attr in &f.attrs {
856                    if attr_str(attr).as_deref() == Some("tags") {
857                        match attr.parse_args::<FieldTagArgs>() {
858                            Ok(args) => skip |= args.skip,
859                            Err(e) => errors.push(e),
860                        }
861                    }
862                }
863                if !skip {
864                    let ty = &f.ty;
865                    if type_contains_generics(GContext { g, always: false }, ty) {
866                        generics.make_where_clause().predicates.push(
867                            parse_quote_spanned! { ty.span() =>
868                                #ty: ::object_rainbow::Tagged
869                            },
870                        );
871                    }
872                }
873            }
874        }
875        Data::Enum(data) => {
876            for v in data.variants.iter() {
877                for f in v.fields.iter() {
878                    let mut skip = false;
879                    for attr in &f.attrs {
880                        if attr_str(attr).as_deref() == Some("tags") {
881                            match attr.parse_args::<FieldTagArgs>() {
882                                Ok(args) => skip |= args.skip,
883                                Err(e) => errors.push(e),
884                            }
885                        }
886                    }
887                    if !skip {
888                        let ty = &f.ty;
889                        if type_contains_generics(GContext { g, always: false }, ty) {
890                            generics.make_where_clause().predicates.push(
891                                parse_quote_spanned! { ty.span() =>
892                                    #ty: ::object_rainbow::Tagged
893                                },
894                            );
895                        }
896                    }
897                }
898            }
899        }
900        Data::Union(data) => {
901            return Err(Error::new_spanned(
902                data.union_token,
903                "`union`s are not supported",
904            ));
905        }
906    }
907    Ok(generics)
908}
909
910struct StructTagArgs {
911    tags: Vec<LitStr>,
912}
913
914impl Parse for StructTagArgs {
915    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
916        let mut tags = Vec::new();
917        while !input.is_empty() {
918            let tag = input.parse::<LitStr>()?;
919            tags.push(tag);
920            if !input.is_empty() {
921                input.parse::<Comma>()?;
922            }
923        }
924        Ok(Self { tags })
925    }
926}
927
928fn fields_tags(fields: &syn::Fields) -> Vec<proc_macro2::TokenStream> {
929    fields
930        .iter()
931        .filter_map(|f| {
932            let mut skip = false;
933            for attr in &f.attrs {
934                if attr_str(attr).as_deref() == Some("tags") {
935                    skip |= attr.parse_args::<FieldTagArgs>().ok()?.skip;
936                }
937            }
938            let ty = &f.ty;
939            (!skip).then_some(quote! { <#ty as ::object_rainbow::Tagged>::TAGS })
940        })
941        .collect()
942}
943
944fn gen_tags(data: &Data, attrs: &[Attribute], errors: &mut Vec<Error>) -> proc_macro2::TokenStream {
945    match data {
946        Data::Struct(data) => {
947            let mut tags = Vec::new();
948            for attr in attrs {
949                if attr_str(attr).as_deref() == Some("tags") {
950                    match attr.parse_args::<StructTagArgs>() {
951                        Ok(mut args) => tags.append(&mut args.tags),
952                        Err(e) => errors.push(e),
953                    }
954                }
955            }
956            let nested = fields_tags(&data.fields);
957            if nested.len() == 1 && tags.is_empty() {
958                let nested = nested.into_iter().next().unwrap();
959                quote! {
960                    #nested
961                }
962            } else {
963                quote! {
964                    ::object_rainbow::Tags(&[#(#tags),*], &[#(&#nested),*])
965                }
966            }
967        }
968        Data::Enum(data) => {
969            let mut tags = Vec::new();
970            for attr in attrs {
971                if attr_str(attr).as_deref() == Some("tags") {
972                    match attr.parse_args::<StructTagArgs>() {
973                        Ok(mut args) => tags.append(&mut args.tags),
974                        Err(e) => errors.push(e),
975                    }
976                }
977            }
978            let mut nested: Vec<_> = data
979                .variants
980                .iter()
981                .flat_map(|v| fields_tags(&v.fields))
982                .collect();
983            let kind_tags = quote! {
984                <
985                    <
986                        <
987                            Self
988                            as
989                            ::object_rainbow::Enum
990                        >::Kind
991                        as
992                        ::object_rainbow::enumkind::EnumKind
993                    >::Tag
994                    as  ::object_rainbow::Tagged
995                >::TAGS
996            };
997            nested.insert(0, kind_tags);
998            if nested.len() == 1 && tags.is_empty() {
999                let nested = nested.into_iter().next().unwrap();
1000                quote! {
1001                    #nested
1002                }
1003            } else {
1004                quote! {
1005                    ::object_rainbow::Tags(&[#(#tags),*], &[#(&#nested),*])
1006                }
1007            }
1008        }
1009        Data::Union(data) => {
1010            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1011        }
1012    }
1013}
1014
1015/// ```rust
1016/// use object_rainbow::Size;
1017///
1018/// #[derive(Size)]
1019/// struct Three<A, B, C> {
1020///     a: A,
1021///     b: B,
1022///     c: C,
1023/// }
1024///
1025/// object_rainbow::assert_impl!(
1026///     impl<A, B, C> Size for Three<A, B, C>
1027///     where
1028///         A: Size<Size = typenum::U2>,
1029///         B: Size<Size = typenum::U3>,
1030///         C: Size<Size = typenum::U7>,
1031///     {}
1032/// );
1033///
1034/// assert_eq!(Three::<[u8; 2], [u8; 3], [u8; 7]>::SIZE, 12);
1035/// ```
1036#[proc_macro_derive(Size)]
1037pub fn derive_size(input: TokenStream) -> TokenStream {
1038    let input = parse_macro_input!(input as DeriveInput);
1039    let name = input.ident;
1040    let size_arr = gen_size_arr(&input.data);
1041    let size = gen_size(&input.data);
1042    let (generics, is_enum) = match bounds_size(input.generics.clone(), &input.data, &size_arr) {
1043        Ok(g) => g,
1044        Err(e) => return e.into_compile_error().into(),
1045    };
1046    let (_, ty_generics, where_clause) = generics.split_for_impl();
1047    let mut generics = input.generics;
1048    if is_enum {
1049        generics.params.push(parse_quote!(
1050            __Output: ::object_rainbow::typenum::Unsigned
1051        ));
1052    }
1053    let (impl_generics, _, _) = generics.split_for_impl();
1054    let target = parse_for(&name, &input.attrs);
1055    let output = quote! {
1056        const _: () = {
1057            use ::object_rainbow::typenum::tarr;
1058
1059            #[automatically_derived]
1060            impl #impl_generics ::object_rainbow::Size for #target #ty_generics #where_clause {
1061                const SIZE: usize = #size;
1062
1063                type Size = <#size_arr as ::object_rainbow::typenum::FoldAdd>::Output;
1064            }
1065        };
1066    };
1067    TokenStream::from(output)
1068}
1069
1070fn bounds_size(
1071    mut generics: Generics,
1072    data: &Data,
1073    size_arr: &proc_macro2::TokenStream,
1074) -> syn::Result<(Generics, bool)> {
1075    let g = &bounds_g(&generics);
1076    let is_enum = match data {
1077        Data::Struct(data) => {
1078            for f in data.fields.iter() {
1079                let ty = &f.ty;
1080                if type_contains_generics(GContext { g, always: false }, ty) {
1081                    generics.make_where_clause().predicates.push(
1082                        parse_quote_spanned! { ty.span() =>
1083                            #ty: ::object_rainbow::Size
1084                        },
1085                    );
1086                }
1087            }
1088            generics.make_where_clause().predicates.push(parse_quote!(
1089                #size_arr: ::object_rainbow::typenum::FoldAdd<
1090                    Output: ::object_rainbow::typenum::Unsigned
1091                >
1092            ));
1093            false
1094        }
1095        Data::Enum(data) => {
1096            for v in data.variants.iter() {
1097                for f in v.fields.iter() {
1098                    let ty = &f.ty;
1099                    if type_contains_generics(GContext { g, always: false }, ty) {
1100                        generics.make_where_clause().predicates.push(
1101                            parse_quote_spanned! { ty.span() =>
1102                                #ty: ::object_rainbow::Size
1103                            },
1104                        );
1105                    }
1106                }
1107            }
1108            for v in data.variants.iter().skip(1) {
1109                let arr = fields_size_arr(&v.fields, true);
1110                generics.make_where_clause().predicates.push(parse_quote!(
1111                    #arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
1112                ));
1113            }
1114            generics.make_where_clause().predicates.push(parse_quote!(
1115                #size_arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
1116            ));
1117            true
1118        }
1119        Data::Union(data) => {
1120            return Err(Error::new_spanned(
1121                data.union_token,
1122                "`union`s are not supported",
1123            ));
1124        }
1125    };
1126    Ok((generics, is_enum))
1127}
1128
1129fn fields_size_arr(fields: &syn::Fields, as_enum: bool) -> proc_macro2::TokenStream {
1130    let kind_size = quote! {
1131        <
1132            <
1133                <
1134                    Self
1135                    as
1136                    ::object_rainbow::Enum
1137                >::Kind
1138                as
1139                ::object_rainbow::enumkind::EnumKind
1140            >::Tag
1141            as  ::object_rainbow::Size
1142        >::Size
1143    };
1144    if fields.is_empty() {
1145        return if as_enum {
1146            quote! { tarr![#kind_size, ::object_rainbow::typenum::consts::U0] }
1147        } else {
1148            quote! { tarr![::object_rainbow::typenum::consts::U0] }
1149        };
1150    }
1151    let size_arr = fields.iter().map(|f| {
1152        let ty = &f.ty;
1153        quote! { <#ty as ::object_rainbow::Size>::Size }
1154    });
1155    if as_enum {
1156        quote! { tarr![#kind_size, ::object_rainbow::typenum::consts::U0, #(#size_arr),*] }
1157    } else {
1158        quote! { tarr![::object_rainbow::typenum::consts::U0, #(#size_arr),*] }
1159    }
1160}
1161
1162fn gen_size_arr(data: &Data) -> proc_macro2::TokenStream {
1163    match data {
1164        Data::Struct(data) => fields_size_arr(&data.fields, false),
1165        Data::Enum(data) => {
1166            if let Some(v) = data.variants.first() {
1167                fields_size_arr(&v.fields, true)
1168            } else {
1169                Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
1170                    .into_compile_error()
1171            }
1172        }
1173        Data::Union(data) => {
1174            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1175        }
1176    }
1177}
1178
1179fn fields_size(fields: &syn::Fields) -> proc_macro2::TokenStream {
1180    if fields.is_empty() {
1181        return quote! {0};
1182    }
1183    let size = fields.iter().map(|f| {
1184        let ty = &f.ty;
1185        quote! { <#ty as ::object_rainbow::Size>::SIZE }
1186    });
1187    quote! {
1188        #(#size)+*
1189    }
1190}
1191
1192fn gen_size(data: &Data) -> proc_macro2::TokenStream {
1193    match data {
1194        Data::Struct(data) => fields_size(&data.fields),
1195        Data::Enum(data) => {
1196            if let Some(v) = data.variants.first() {
1197                let size = fields_size(&v.fields);
1198                let kind_size = quote! {
1199                    <
1200                        <
1201                            <
1202                                Self
1203                                as
1204                                ::object_rainbow::Enum
1205                            >::Kind
1206                            as
1207                            ::object_rainbow::enumkind::EnumKind
1208                        >::Tag
1209                        as  ::object_rainbow::Size
1210                    >::SIZE
1211                };
1212                quote! { #kind_size + #size }
1213            } else {
1214                Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
1215                    .into_compile_error()
1216            }
1217        }
1218        Data::Union(data) => {
1219            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1220        }
1221    }
1222}
1223
1224/// ```rust
1225/// use object_rainbow::{Parse, ParseInline, ParseInput};
1226///
1227/// #[derive(Parse)]
1228/// struct Three<A, B, C> {
1229///     a: A,
1230///     b: B,
1231///     c: C,
1232/// }
1233///
1234/// object_rainbow::assert_impl!(
1235///     impl<A, B, C, I> Parse<I> for Three<A, B, C>
1236///     where
1237///         A: ParseInline<I>,
1238///         B: ParseInline<I>,
1239///         C: Parse<I>,
1240///         I: ParseInput,
1241///     {}
1242/// );
1243/// ```
1244#[proc_macro_derive(Parse, attributes(parse))]
1245pub fn derive_parse(input: TokenStream) -> TokenStream {
1246    let input = parse_macro_input!(input as DeriveInput);
1247    let name = input.ident;
1248    let generics = input.generics.clone();
1249    let (_, ty_generics, _) = generics.split_for_impl();
1250    let (inp, generics) = match bounds_parse(input.generics, &input.data, &input.attrs) {
1251        Ok(g) => g,
1252        Err(e) => return e.into_compile_error().into(),
1253    };
1254    let (parse, enum_parse) = gen_parse(&input.data, &inp);
1255    let (impl_generics, _, where_clause) = generics.split_for_impl();
1256    let target = parse_for(&name, &input.attrs);
1257    let enum_parse = enum_parse.map(|enum_parse| {
1258        quote! {
1259            #[automatically_derived]
1260            impl #impl_generics ::object_rainbow::enumkind::EnumParse<#inp> for #target #ty_generics
1261            #where_clause
1262            {
1263                fn enum_parse(
1264                    kind: <Self as ::object_rainbow::Enum>::Kind, mut input: #inp,
1265                ) -> ::object_rainbow::Result<Self> {
1266                    #enum_parse
1267                }
1268            }
1269        }
1270    });
1271    let output = quote! {
1272        const _: () = {
1273            #[automatically_derived]
1274            impl #impl_generics ::object_rainbow::Parse<#inp> for #target #ty_generics
1275            #where_clause
1276            {
1277                fn parse(mut input: #inp) -> ::object_rainbow::Result<Self> {
1278                    #parse
1279                }
1280            }
1281
1282            #enum_parse
1283        };
1284    };
1285    TokenStream::from(output)
1286}
1287
1288#[derive(Debug, FromMeta)]
1289#[darling(derive_syn_parse)]
1290struct ContainerParseArgs {
1291    #[darling(default)]
1292    unchecked: bool,
1293    #[darling(default)]
1294    bound: Option<LitStr>,
1295    #[darling(default)]
1296    generic: Option<LitStr>,
1297    #[darling(default)]
1298    input: Option<LitStr>,
1299}
1300
1301fn parse_parse_args(
1302    attrs: &[Attribute],
1303) -> syn::Result<(bool, Ident, Vec<WherePredicate>, Vec<GenericParam>)> {
1304    let mut u = false;
1305    let mut inp = parse_quote!(__I);
1306    let mut wheres = Vec::new();
1307    let mut ig = Vec::new();
1308    for attr in attrs {
1309        if attr_str(attr).as_deref() == Some("parse") {
1310            let ContainerParseArgs {
1311                unchecked,
1312                input,
1313                bound,
1314                generic,
1315            } = attr.parse_args()?;
1316            if unchecked {
1317                u = true;
1318            }
1319            if let Some(input) = input {
1320                inp = input.parse()?;
1321            }
1322            if let Some(bound) = bound {
1323                wheres.push(bound.parse()?);
1324            }
1325            if let Some(generic) = generic {
1326                ig.push(generic.parse()?);
1327            }
1328        }
1329    }
1330    Ok((u, inp, wheres, ig))
1331}
1332
1333#[derive(Debug, FromMeta)]
1334#[darling(derive_syn_parse)]
1335struct ParseArgs {
1336    bound: Option<Type>,
1337    #[darling(default)]
1338    unchecked: bool,
1339    with: Option<Expr>,
1340}
1341
1342fn bounds_parse(
1343    mut generics: Generics,
1344    data: &Data,
1345    attrs: &[Attribute],
1346) -> syn::Result<(Ident, Generics)> {
1347    let (recursive, _, _, _) = parse_recursive_inline(attrs)?;
1348    let (u, inp, wheres, ig) = parse_parse_args(attrs)?;
1349    let tr = |last| match (last, recursive) {
1350        (true, true) => {
1351            quote!(::object_rainbow::Parse<#inp> + ::object_rainbow::Object<#inp::Extra>)
1352        }
1353        (true, false) => quote!(::object_rainbow::Parse<#inp>),
1354        (false, true) => {
1355            quote!(::object_rainbow::ParseInline<#inp> + ::object_rainbow::Inline<#inp::Extra>)
1356        }
1357        (false, false) => quote!(::object_rainbow::ParseInline<#inp>),
1358    };
1359    match data {
1360        Data::Struct(data) => {
1361            let last_at = data.fields.len().saturating_sub(1);
1362            'field: for (i, f) in data.fields.iter().enumerate() {
1363                let last = i == last_at;
1364                let ty = &f.ty;
1365                let mut b = None;
1366                for attr in &f.attrs {
1367                    if attr_str(attr).as_deref() == Some("parse") {
1368                        let ParseArgs {
1369                            bound, unchecked, ..
1370                        } = attr.parse_args::<ParseArgs>()?;
1371                        if unchecked {
1372                            continue 'field;
1373                        }
1374                        if let Some(bound) = bound {
1375                            b = Some(bound);
1376                        }
1377                    }
1378                }
1379                if let Some(bound) = b {
1380                    generics.make_where_clause().predicates.push(
1381                        parse_quote_spanned! { ty.span() =>
1382                            (#ty, #inp::Extra): ::object_rainbow::BoundPair<
1383                                T = #ty, E = #inp::Extra
1384                            > + #bound
1385                        },
1386                    );
1387                } else {
1388                    if u {
1389                        continue 'field;
1390                    }
1391                    let tr = tr(last);
1392                    generics.make_where_clause().predicates.push(
1393                        parse_quote_spanned! { ty.span() =>
1394                            #ty: #tr
1395                        },
1396                    );
1397                }
1398            }
1399        }
1400        Data::Enum(data) => {
1401            for v in data.variants.iter() {
1402                let last_at = v.fields.len().saturating_sub(1);
1403                'field: for (i, f) in v.fields.iter().enumerate() {
1404                    let ty = &f.ty;
1405                    let mut b = None;
1406                    for attr in &f.attrs {
1407                        if attr_str(attr).as_deref() == Some("parse") {
1408                            let ParseArgs {
1409                                bound, unchecked, ..
1410                            } = attr.parse_args::<ParseArgs>()?;
1411                            if unchecked {
1412                                continue 'field;
1413                            }
1414                            if let Some(bound) = bound {
1415                                b = Some(bound);
1416                            }
1417                        }
1418                    }
1419                    if let Some(bound) = b {
1420                        generics.make_where_clause().predicates.push(
1421                            parse_quote_spanned! { ty.span() =>
1422                                (#ty, #inp::Extra): ::object_rainbow::BoundPair<
1423                                    T = #ty, E = #inp::Extra
1424                                > + #bound
1425                            },
1426                        );
1427                    } else {
1428                        if u {
1429                            continue 'field;
1430                        }
1431                        let last = i == last_at;
1432                        let tr = tr(last);
1433                        generics.make_where_clause().predicates.push(
1434                            parse_quote_spanned! { ty.span() =>
1435                                #ty: #tr
1436                            },
1437                        );
1438                    }
1439                }
1440            }
1441        }
1442        Data::Union(data) => {
1443            return Err(Error::new_spanned(
1444                data.union_token,
1445                "`union`s are not supported",
1446            ));
1447        }
1448    }
1449    generics.params.push(if recursive {
1450        parse_quote!(#inp: ::object_rainbow::PointInput<
1451            Extra: ::core::marker::Send + ::core::marker::Sync + ::core::clone::Clone
1452        >)
1453    } else {
1454        parse_quote!(#inp: ::object_rainbow::ParseInput)
1455    });
1456    for bound in wheres {
1457        generics.make_where_clause().predicates.push(bound);
1458    }
1459    generics.params.extend(ig);
1460    Ok((inp, generics))
1461}
1462
1463fn gen_parse(
1464    data: &Data,
1465    inp: &Ident,
1466) -> (proc_macro2::TokenStream, Option<proc_macro2::TokenStream>) {
1467    match data {
1468        Data::Struct(data) => {
1469            let arm = fields_parse(&data.fields, inp);
1470            (quote! { Ok(Self #arm)}, None)
1471        }
1472        Data::Enum(data) => {
1473            let parse = data.variants.iter().map(|v| {
1474                let ident = &v.ident;
1475                let arm = fields_parse(&v.fields, inp);
1476                quote! {
1477                    <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
1478                }
1479            });
1480            (
1481                quote! {
1482                    ::object_rainbow::enumkind::EnumParse::parse_as_enum(input)
1483                },
1484                Some(quote! {
1485                    Ok(match kind {
1486                        #(#parse)*
1487                    })
1488                }),
1489            )
1490        }
1491        Data::Union(data) => (
1492            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error(),
1493            None,
1494        ),
1495    }
1496}
1497
1498fn fields_parse(fields: &syn::Fields, inp: &Ident) -> proc_macro2::TokenStream {
1499    let last_at = fields.len().saturating_sub(1);
1500    match fields {
1501        syn::Fields::Named(fields) => {
1502            let parse = fields.named.iter().enumerate().map(|(i, f)| {
1503                let last = i == last_at;
1504                let ty = &f.ty;
1505                let mut w = None;
1506                let mut b = None;
1507                for attr in &f.attrs {
1508                    if attr_str(attr).as_deref() == Some("parse") {
1509                        let ParseArgs { with, bound, .. } = match attr.parse_args::<ParseArgs>() {
1510                            Ok(args) => args,
1511                            Err(e) => return e.into_compile_error(),
1512                        };
1513                        if let Some(with) = with {
1514                            w = Some(with);
1515                        }
1516                        if let Some(bound) = bound {
1517                            b = Some(bound);
1518                        }
1519                    }
1520                }
1521                let i = f.ident.as_ref().unwrap();
1522                if let Some(with) = w {
1523                    let arg = if last {
1524                        quote!(input)
1525                    } else {
1526                        quote!(&mut input)
1527                    };
1528                    if let Some(bound) = b {
1529                        quote_spanned! { f.ty.span() =>
1530                            #i: <(#ty, #inp::Extra) as #bound>::#with(#arg)?
1531                        }
1532                    } else {
1533                        quote_spanned! { f.ty.span() =>
1534                            #i: #with(#arg)?
1535                        }
1536                    }
1537                } else {
1538                    let method = if last {
1539                        quote!(parse)
1540                    } else {
1541                        quote!(parse_inline)
1542                    };
1543                    quote_spanned! { f.ty.span() =>
1544                        #i: input.#method()?
1545                    }
1546                }
1547            });
1548            quote! { { #(#parse),* } }
1549        }
1550        syn::Fields::Unnamed(fields) => {
1551            let parse = fields.unnamed.iter().enumerate().map(|(i, f)| {
1552                let ty = &f.ty;
1553                let mut w = None;
1554                let mut b = None;
1555                for attr in &f.attrs {
1556                    if attr_str(attr).as_deref() == Some("parse") {
1557                        let ParseArgs { with, bound, .. } = match attr.parse_args::<ParseArgs>() {
1558                            Ok(args) => args,
1559                            Err(e) => return e.into_compile_error(),
1560                        };
1561                        if let Some(with) = with {
1562                            w = Some(with);
1563                        }
1564                        if let Some(bound) = bound {
1565                            b = Some(bound);
1566                        }
1567                    }
1568                }
1569                let last = i == last_at;
1570                if let Some(with) = w {
1571                    let arg = if last {
1572                        quote!(input)
1573                    } else {
1574                        quote!(&mut input)
1575                    };
1576                    if let Some(bound) = b {
1577                        quote_spanned! { f.ty.span() =>
1578                            <(#ty, #inp::Extra) as #bound>::#with(#arg)?
1579                        }
1580                    } else {
1581                        quote_spanned! { f.ty.span() =>
1582                            #with(#arg)?
1583                        }
1584                    }
1585                } else {
1586                    let method = if last {
1587                        quote!(parse)
1588                    } else {
1589                        quote!(parse_inline)
1590                    };
1591                    quote_spanned! { f.ty.span() =>
1592                        input.#method()?
1593                    }
1594                }
1595            });
1596            quote! { (#(#parse),*) }
1597        }
1598        syn::Fields::Unit => quote! {},
1599    }
1600}
1601
1602/// ```rust
1603/// use object_rainbow::{Parse, ParseInline, ParseInput};
1604///
1605/// #[derive(Parse, ParseInline)]
1606/// struct Three<A, B, C> {
1607///     a: A,
1608///     b: B,
1609///     c: C,
1610/// }
1611///
1612/// object_rainbow::assert_impl!(
1613///     impl<A, B, C, I> ParseInline<I> for Three<A, B, C>
1614///     where
1615///         A: ParseInline<I>,
1616///         B: ParseInline<I>,
1617///         C: ParseInline<I>,
1618///         I: ParseInput,
1619///     {}
1620/// );
1621/// ```
1622#[proc_macro_derive(ParseInline, attributes(parse))]
1623pub fn derive_parse_inline(input: TokenStream) -> TokenStream {
1624    let input = parse_macro_input!(input as DeriveInput);
1625    let name = input.ident;
1626    let generics = input.generics.clone();
1627    let (_, ty_generics, _) = generics.split_for_impl();
1628    let (inp, generics) = match bounds_parse_inline(input.generics, &input.data, &input.attrs) {
1629        Ok(g) => g,
1630        Err(e) => return e.into_compile_error().into(),
1631    };
1632    let (parse_inline, enum_parse_inline) = gen_parse_inline(&input.data);
1633    let (impl_generics, _, where_clause) = generics.split_for_impl();
1634    let target = parse_for(&name, &input.attrs);
1635    let enum_parse_inline = enum_parse_inline.map(|enum_parse_inline| {
1636        quote! {
1637            #[automatically_derived]
1638            impl #impl_generics ::object_rainbow::enumkind::EnumParseInline<#inp>
1639            for #target #ty_generics #where_clause {
1640                fn enum_parse_inline(
1641                    kind: <Self as ::object_rainbow::Enum>::Kind, input: &mut #inp,
1642                ) -> ::object_rainbow::Result<Self> {
1643                    #enum_parse_inline
1644                }
1645            }
1646        }
1647    });
1648    let output = quote! {
1649        #[automatically_derived]
1650        impl #impl_generics ::object_rainbow::ParseInline<#inp>
1651        for #target #ty_generics #where_clause {
1652            fn parse_inline(input: &mut #inp) -> ::object_rainbow::Result<Self> {
1653                #parse_inline
1654            }
1655        }
1656
1657        #enum_parse_inline
1658    };
1659    TokenStream::from(output)
1660}
1661
1662fn bounds_parse_inline(
1663    mut generics: Generics,
1664    data: &Data,
1665    attrs: &[Attribute],
1666) -> syn::Result<(Ident, Generics)> {
1667    let (recursive, _, _, _) = parse_recursive_inline(attrs)?;
1668    let (u, inp, wheres, ig) = parse_parse_args(attrs)?;
1669    let tr = if recursive {
1670        quote!(::object_rainbow::ParseInline<#inp> + ::object_rainbow::Inline<#inp::Extra>)
1671    } else {
1672        quote!(::object_rainbow::ParseInline<#inp>)
1673    };
1674    match data {
1675        Data::Struct(data) => {
1676            'field: for f in data.fields.iter() {
1677                let ty = &f.ty;
1678                let mut b = None;
1679                for attr in &f.attrs {
1680                    if attr_str(attr).as_deref() == Some("parse") {
1681                        let ParseArgs {
1682                            bound, unchecked, ..
1683                        } = attr.parse_args::<ParseArgs>()?;
1684                        if unchecked {
1685                            continue 'field;
1686                        }
1687                        if let Some(bound) = bound {
1688                            b = Some(bound);
1689                        }
1690                    }
1691                }
1692                if let Some(bound) = b {
1693                    generics.make_where_clause().predicates.push(
1694                        parse_quote_spanned! { ty.span() =>
1695                            (#ty, #inp::Extra): #bound
1696                        },
1697                    );
1698                } else {
1699                    if u {
1700                        continue 'field;
1701                    }
1702                    generics.make_where_clause().predicates.push(
1703                        parse_quote_spanned! { ty.span() =>
1704                            #ty: #tr
1705                        },
1706                    );
1707                }
1708            }
1709        }
1710        Data::Enum(data) => {
1711            for v in data.variants.iter() {
1712                'field: for f in v.fields.iter() {
1713                    let ty = &f.ty;
1714                    let mut b = None;
1715                    for attr in &f.attrs {
1716                        if attr_str(attr).as_deref() == Some("parse") {
1717                            let ParseArgs {
1718                                bound, unchecked, ..
1719                            } = attr.parse_args::<ParseArgs>()?;
1720                            if unchecked {
1721                                continue 'field;
1722                            }
1723                            if let Some(bound) = bound {
1724                                b = Some(bound);
1725                            }
1726                        }
1727                    }
1728                    if let Some(bound) = b {
1729                        generics.make_where_clause().predicates.push(
1730                            parse_quote_spanned! { ty.span() =>
1731                                (#ty, #inp::Extra): #bound
1732                            },
1733                        );
1734                    } else {
1735                        if u {
1736                            continue 'field;
1737                        }
1738                        generics.make_where_clause().predicates.push(
1739                            parse_quote_spanned! { ty.span() =>
1740                                #ty: #tr
1741                            },
1742                        );
1743                    }
1744                }
1745            }
1746        }
1747        Data::Union(data) => {
1748            return Err(Error::new_spanned(
1749                data.union_token,
1750                "`union`s are not supported",
1751            ));
1752        }
1753    }
1754    generics.params.push(if recursive {
1755        parse_quote!(#inp: ::object_rainbow::PointInput<
1756            Extra: ::core::marker::Send + ::core::marker::Sync
1757        >)
1758    } else {
1759        parse_quote!(#inp: ::object_rainbow::ParseInput)
1760    });
1761    for bound in wheres {
1762        generics.make_where_clause().predicates.push(bound);
1763    }
1764    for generic in ig {
1765        generics.params.push(parse_quote!(#generic));
1766    }
1767    Ok((inp, generics))
1768}
1769
1770fn fields_parse_inline(fields: &syn::Fields) -> proc_macro2::TokenStream {
1771    match fields {
1772        syn::Fields::Named(fields) => {
1773            let parse = fields.named.iter().map(|f| {
1774                let i = f.ident.as_ref().unwrap();
1775                quote_spanned! { f.ty.span() =>
1776                    #i: input.parse_inline()?
1777                }
1778            });
1779            quote! { { #(#parse),* } }
1780        }
1781        syn::Fields::Unnamed(fields) => {
1782            let parse = fields.unnamed.iter().map(|f| {
1783                quote_spanned! { f.ty.span() =>
1784                    input.parse_inline()?
1785                }
1786            });
1787            quote! { (#(#parse),*) }
1788        }
1789        syn::Fields::Unit => quote! {},
1790    }
1791}
1792
1793fn gen_parse_inline(data: &Data) -> (proc_macro2::TokenStream, Option<proc_macro2::TokenStream>) {
1794    match data {
1795        Data::Struct(data) => {
1796            let arm = fields_parse_inline(&data.fields);
1797            (quote! { Ok(Self #arm) }, None)
1798        }
1799        Data::Enum(data) => {
1800            let parse_inline = data.variants.iter().map(|v| {
1801                let ident = &v.ident;
1802                let arm = fields_parse_inline(&v.fields);
1803                quote! {
1804                    <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
1805                }
1806            });
1807            (
1808                quote! {
1809                    ::object_rainbow::enumkind::EnumParseInline::parse_as_inline_enum(input)
1810                },
1811                Some(quote! {
1812                    Ok(match kind {
1813                        #(#parse_inline)*
1814                    })
1815                }),
1816            )
1817        }
1818        Data::Union(data) => (
1819            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error(),
1820            None,
1821        ),
1822    }
1823}
1824
1825/// ```rust
1826/// use object_rainbow::{Parse, ParseAsInline, ParseInline, ParseInput};
1827///
1828/// #[derive(ParseAsInline)]
1829/// struct Thing<T> {
1830///     inner: T,
1831/// }
1832///
1833/// object_rainbow::assert_impl!(
1834///     impl<T, I> Parse<I> for Thing<T>
1835///     where
1836///         Thing<T>: ParseInline<I>,
1837///         I: ParseInput,
1838///     {}
1839/// );
1840/// ```
1841#[proc_macro_derive(ParseAsInline)]
1842pub fn derive_parse_as_inline(input: TokenStream) -> TokenStream {
1843    let input = parse_macro_input!(input as DeriveInput);
1844    let name = input.ident;
1845    let generics = input.generics.clone();
1846    let (_, ty_generics, _) = generics.split_for_impl();
1847    let generics = match bounds_parse_as_inline(input.generics, &name) {
1848        Ok(g) => g,
1849        Err(e) => return e.into_compile_error().into(),
1850    };
1851    let (impl_generics, _, where_clause) = generics.split_for_impl();
1852    let target = parse_for(&name, &input.attrs);
1853    let output = quote! {
1854        #[automatically_derived]
1855        impl #impl_generics ::object_rainbow::Parse<__I> for #target #ty_generics #where_clause {
1856            fn parse(input: __I) -> ::object_rainbow::Result<Self> {
1857                ::object_rainbow::ParseInline::<__I>::parse_as_inline(input)
1858            }
1859        }
1860    };
1861    TokenStream::from(output)
1862}
1863
1864fn bounds_parse_as_inline(mut generics: Generics, name: &Ident) -> syn::Result<Generics> {
1865    generics
1866        .make_where_clause()
1867        .predicates
1868        .push(parse_quote_spanned! { name.span() =>
1869            Self: ::object_rainbow::ParseInline::<__I>
1870        });
1871    generics
1872        .params
1873        .push(parse_quote!(__I: ::object_rainbow::ParseInput));
1874    Ok(generics)
1875}
1876
1877fn parse_path(attr: &Attribute) -> syn::Result<Type> {
1878    attr.parse_args::<LitStr>()?.parse()
1879}
1880
1881fn attr_str(attr: &Attribute) -> Option<String> {
1882    Some(attr.path().get_ident()?.to_string())
1883}
1884
1885/// ```rust
1886/// use std::num::NonZero;
1887///
1888/// use object_rainbow::{Enum, MaybeHasNiche, ToOutput};
1889///
1890/// #[derive(Enum, ToOutput, MaybeHasNiche)]
1891/// enum WithDefault {
1892///     A(u8),
1893///     B(bool),
1894/// }
1895///
1896/// assert_eq!(Some(WithDefault::A(32)).vec(), [0, 32]);
1897/// assert_eq!(Some(WithDefault::B(true)).vec(), [1, 1]);
1898/// assert_eq!(None::<WithDefault>.vec(), [2, 0]);
1899///
1900/// #[derive(Enum, ToOutput, MaybeHasNiche)]
1901/// #[enumtag("NonZero<u8>")]
1902/// enum WithNz {
1903///     A(u8),
1904///     B(bool),
1905/// }
1906///
1907/// assert_eq!(None::<WithNz>.vec(), [0, 0]);
1908/// assert_eq!(Some(WithNz::A(32)).vec(), [1, 32]);
1909/// assert_eq!(Some(WithNz::B(true)).vec(), [2, 1]);
1910///
1911/// #[derive(Enum, ToOutput, MaybeHasNiche)]
1912/// #[enumtag("bool")]
1913/// enum WithBool {
1914///     A(u8),
1915///     B(bool),
1916/// }
1917///
1918/// assert_eq!(Some(WithBool::A(32)).vec(), [0, 32]);
1919/// assert_eq!(Some(WithBool::B(true)).vec(), [1, 1]);
1920/// assert_eq!(None::<WithBool>.vec(), [2, 0]);
1921///
1922/// #[derive(Enum, ToOutput, MaybeHasNiche)]
1923/// #[enumtag("u8")]
1924/// enum WithU8 {
1925///     A(u8),
1926///     B(bool),
1927/// }
1928///
1929/// assert_eq!(Some(WithU8::A(32)).vec(), [0, 32]);
1930/// assert_eq!(Some(WithU8::B(true)).vec(), [1, 1]);
1931/// assert_eq!(None::<WithU8>.vec(), [1, 2]);
1932///
1933/// #[derive(Enum, ToOutput, MaybeHasNiche)]
1934/// #[enumtag("u8")]
1935/// enum WithoutNiche {
1936///     A(u8),
1937///     B(u8),
1938/// }
1939///
1940/// assert_eq!(Some(WithoutNiche::A(32)).vec(), [0, 0, 32]);
1941/// assert_eq!(Some(WithoutNiche::B(1)).vec(), [0, 1, 1]);
1942/// assert_eq!(None::<WithoutNiche>.vec(), [1]);
1943/// ```
1944#[proc_macro_derive(Enum, attributes(enumtag))]
1945pub fn derive_enum(input: TokenStream) -> TokenStream {
1946    let input = parse_macro_input!(input as DeriveInput);
1947    let name = input.ident;
1948    let generics = input.generics.clone();
1949    let (_, ty_generics, _) = generics.split_for_impl();
1950    let generics = input.generics;
1951    let length = gen_length(&input.data);
1952    let variants = gen_variants(&input.data);
1953    let variant_count = gen_variant_count(&input.data);
1954    let to_tag = gen_to_tag(&input.data);
1955    let from_tag = gen_from_tag(&input.data);
1956    let kind = gen_kind(&input.data);
1957    let (impl_generics, _, where_clause) = generics.split_for_impl();
1958    let mut errors = Vec::new();
1959    let mut enumtag = None;
1960    for attr in &input.attrs {
1961        if attr_str(attr).as_deref() == Some("enumtag") {
1962            match parse_path(attr) {
1963                Ok(path) => {
1964                    if enumtag.is_some() {
1965                        errors.push(Error::new_spanned(path, "duplicate tag"));
1966                    } else {
1967                        enumtag = Some(path);
1968                    }
1969                }
1970                Err(e) => errors.push(e),
1971            }
1972        }
1973    }
1974    let enumtag = enumtag.unwrap_or_else(|| {
1975        parse_quote!(
1976            ::object_rainbow::partial_byte_tag::PartialByteTag<#length>
1977        )
1978    });
1979    let errors = errors.into_iter().map(|e| e.into_compile_error());
1980    let target = parse_for(&name, &input.attrs);
1981    let output = quote! {
1982        const _: () = {
1983            #(#errors)*
1984
1985            use ::object_rainbow::enumkind::EnumKind;
1986
1987            #[derive(Clone, Copy, ::object_rainbow::ParseAsInline)]
1988            pub enum __Kind {
1989                #variants
1990            }
1991
1992            #[automatically_derived]
1993            impl ::object_rainbow::enumkind::EnumKind for __Kind {
1994                type Tag = ::object_rainbow::enumkind::EnumTag<
1995                    #enumtag,
1996                    #variant_count,
1997                >;
1998
1999                fn to_tag(self) -> Self::Tag {
2000                    #to_tag
2001                }
2002
2003                fn from_tag(tag: Self::Tag) -> Self {
2004                    #from_tag
2005                }
2006            }
2007
2008            impl<I: ::object_rainbow::ParseInput> ::object_rainbow::ParseInline<I> for __Kind {
2009                fn parse_inline(input: &mut I) -> ::object_rainbow::Result<Self> {
2010                    Ok(::object_rainbow::enumkind::EnumKind::from_tag(input.parse_inline()?))
2011                }
2012            }
2013
2014            #[automatically_derived]
2015            impl #impl_generics ::object_rainbow::Enum for #target #ty_generics #where_clause {
2016                type Kind = __Kind;
2017
2018                fn kind(&self) -> Self::Kind {
2019                    #kind
2020                }
2021            }
2022        };
2023    };
2024    TokenStream::from(output)
2025}
2026
2027fn gen_length(data: &Data) -> proc_macro2::TokenStream {
2028    match data {
2029        Data::Struct(data) => {
2030            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2031        }
2032        Data::Enum(data) => {
2033            let name = format!("U{}", data.variants.len());
2034            let ident = Ident::new(&name, data.variants.span());
2035            quote! { ::object_rainbow::typenum::#ident }
2036        }
2037        Data::Union(data) => {
2038            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2039        }
2040    }
2041}
2042
2043fn gen_variants(data: &Data) -> proc_macro2::TokenStream {
2044    match data {
2045        Data::Struct(data) => {
2046            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2047        }
2048        Data::Enum(data) => {
2049            let variants = data.variants.iter().map(|v| &v.ident);
2050            quote! { #(#variants),* }
2051        }
2052        Data::Union(data) => {
2053            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2054        }
2055    }
2056}
2057
2058fn gen_variant_count(data: &Data) -> proc_macro2::TokenStream {
2059    match data {
2060        Data::Struct(data) => {
2061            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2062        }
2063        Data::Enum(data) => {
2064            let variant_count = data.variants.len();
2065            quote! { #variant_count }
2066        }
2067        Data::Union(data) => {
2068            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2069        }
2070    }
2071}
2072
2073fn gen_to_tag(data: &Data) -> proc_macro2::TokenStream {
2074    match data {
2075        Data::Struct(data) => {
2076            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2077        }
2078        Data::Enum(data) => {
2079            let to_tag = data.variants.iter().enumerate().map(|(i, v)| {
2080                let ident = &v.ident;
2081                quote_spanned! { ident.span() =>
2082                    Self::#ident => ::object_rainbow::enumkind::EnumTag::from_const::<#i>(),
2083                }
2084            });
2085            quote! {
2086                match self {
2087                    #(#to_tag)*
2088                }
2089            }
2090        }
2091        Data::Union(data) => {
2092            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2093        }
2094    }
2095}
2096
2097fn gen_from_tag(data: &Data) -> proc_macro2::TokenStream {
2098    match data {
2099        Data::Struct(data) => {
2100            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2101        }
2102        Data::Enum(data) => {
2103            let from_tag = data.variants.iter().enumerate().map(|(i, v)| {
2104                let ident = &v.ident;
2105                quote_spanned! { ident.span() =>
2106                    #i => Self::#ident,
2107                }
2108            });
2109            quote! {
2110                match tag.to_usize() {
2111                    #(#from_tag)*
2112                    _ => unreachable!(),
2113                }
2114            }
2115        }
2116        Data::Union(data) => {
2117            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2118        }
2119    }
2120}
2121
2122fn gen_kind(data: &Data) -> proc_macro2::TokenStream {
2123    match data {
2124        Data::Struct(data) => {
2125            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2126        }
2127        Data::Enum(data) => {
2128            let variants = data.variants.iter().map(|v| {
2129                let ident = &v.ident;
2130                quote_spanned! { ident.span() =>
2131                    Self::#ident {..} => __Kind::#ident,
2132                }
2133            });
2134            quote! {
2135                match self {
2136                    #(#variants)*
2137                }
2138            }
2139        }
2140        Data::Union(data) => {
2141            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2142        }
2143    }
2144}
2145
2146/// ```rust
2147/// use object_rainbow::{MaybeHasNiche, Size};
2148///
2149/// #[derive(Size, MaybeHasNiche)]
2150/// struct WithHole(bool, u8);
2151///
2152/// #[derive(Size, MaybeHasNiche)]
2153/// struct NoHole(u8, u8);
2154///
2155/// assert_eq!(Option::<WithHole>::SIZE, 2);
2156/// assert_eq!(Option::<NoHole>::SIZE, 3);
2157/// ```
2158#[proc_macro_derive(MaybeHasNiche)]
2159pub fn derive_maybe_has_niche(input: TokenStream) -> TokenStream {
2160    let input = parse_macro_input!(input as DeriveInput);
2161    let name = input.ident;
2162    let mn_array = gen_mn_array(&input.data);
2163    let (_, ty_generics, _) = input.generics.split_for_impl();
2164    let generics = match bounds_maybe_has_niche(input.generics.clone(), &input.data) {
2165        Ok(g) => g,
2166        Err(e) => return e.into_compile_error().into(),
2167    };
2168    let (impl_generics, _, where_clause) = generics.split_for_impl();
2169    let target = parse_for(&name, &input.attrs);
2170    let output = quote! {
2171        const _: () = {
2172            use ::object_rainbow::typenum::tarr;
2173
2174            #[automatically_derived]
2175            impl #impl_generics ::object_rainbow::MaybeHasNiche
2176            for #target #ty_generics #where_clause {
2177                type MnArray = #mn_array;
2178            }
2179        };
2180    };
2181    TokenStream::from(output)
2182}
2183
2184fn bounds_maybe_has_niche(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
2185    match data {
2186        Data::Struct(data) => {
2187            for f in data.fields.iter() {
2188                let ty = &f.ty;
2189                generics
2190                    .make_where_clause()
2191                    .predicates
2192                    .push(parse_quote_spanned! { ty.span() =>
2193                        #ty: ::object_rainbow::MaybeHasNiche<
2194                            MnArray: ::object_rainbow::MnArray<
2195                                MaybeNiche: ::object_rainbow::MaybeNiche
2196                            >
2197                        >
2198                    });
2199            }
2200        }
2201        Data::Enum(data) => {
2202            generics.params.push(parse_quote!(
2203                __N: ::object_rainbow::typenum::Unsigned
2204            ));
2205            for (i, v) in data.variants.iter().enumerate() {
2206                let mn_array = fields_mn_array(&v.fields, Some(i));
2207                generics
2208                    .make_where_clause()
2209                    .predicates
2210                    .push(parse_quote_spanned! { v.span() =>
2211                        #mn_array: ::object_rainbow::MnArray<
2212                            MaybeNiche: ::object_rainbow::NicheOr<N = __N>
2213                        >
2214                    });
2215                for f in v.fields.iter() {
2216                    let ty = &f.ty;
2217                    generics.make_where_clause().predicates.push(
2218                        parse_quote_spanned! { ty.span() =>
2219                            #ty: ::object_rainbow::MaybeHasNiche<
2220                                MnArray: ::object_rainbow::MnArray<
2221                                    MaybeNiche: ::object_rainbow::MaybeNiche
2222                                >
2223                            >
2224                        },
2225                    );
2226                }
2227            }
2228        }
2229        Data::Union(data) => {
2230            return Err(Error::new_spanned(
2231                data.union_token,
2232                "`union`s are not supported",
2233            ));
2234        }
2235    }
2236    Ok(generics)
2237}
2238
2239fn fields_mn_array(fields: &syn::Fields, variant: Option<usize>) -> proc_macro2::TokenStream {
2240    let mn_array = fields.iter().map(|f| {
2241        let ty = &f.ty;
2242        quote! {
2243            <
2244                <
2245                    #ty
2246                    as
2247                    ::object_rainbow::MaybeHasNiche
2248                >::MnArray
2249                as
2250                ::object_rainbow::MnArray
2251            >::MaybeNiche
2252        }
2253    });
2254    if let Some(variant) = variant {
2255        let kind_niche = quote! {
2256            ::object_rainbow::AutoEnumNiche<Self, #variant>
2257        };
2258        quote! {
2259            tarr![
2260                #kind_niche,
2261                ::object_rainbow::NoNiche<::object_rainbow::HackNiche<#variant>>, #(#mn_array),*
2262            ]
2263        }
2264    } else {
2265        quote! { tarr![#(#mn_array),*] }
2266    }
2267}
2268
2269fn gen_mn_array(data: &Data) -> proc_macro2::TokenStream {
2270    match data {
2271        Data::Struct(data) => fields_mn_array(&data.fields, None),
2272        Data::Enum(data) => {
2273            let mn_array = data.variants.iter().enumerate().map(|(i, v)| {
2274                let mn_array = fields_mn_array(&v.fields, Some(i));
2275                quote! { <#mn_array as ::object_rainbow::MnArray>::MaybeNiche }
2276            });
2277            quote! {
2278                ::object_rainbow::NicheFoldOrArray<tarr![#(#mn_array),*]>
2279            }
2280        }
2281        Data::Union(data) => {
2282            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
2283        }
2284    }
2285}
2286
2287#[proc_macro_attribute]
2288pub fn derive_for_wrapped(args: TokenStream, input: TokenStream) -> TokenStream {
2289    let input = parse_macro_input!(input as ItemTrait);
2290    let sup = if args.is_empty() {
2291        let sup = input.supertraits.clone();
2292        quote!(#sup)
2293    } else {
2294        args.into()
2295    };
2296    let name = input.ident.clone();
2297    let generics = input.generics.clone();
2298    let (_, ty_generics, _) = generics.split_for_impl();
2299    let mut derived = Vec::new();
2300    for (path, extra) in [
2301        (
2302            quote!(map_extra::MappedExtra),
2303            vec![(quote!(__M), quote!(#sup))],
2304        ),
2305        (quote!(length_prefixed::Lp), vec![]),
2306    ] {
2307        let mut generics = input.generics.clone();
2308        generics.params.push(parse_quote! {
2309            __T: #name #ty_generics
2310        });
2311        for (i, ty) in &extra {
2312            generics.params.push(parse_quote! {
2313                #i: #ty
2314            });
2315        }
2316        let (impl_generics, _, where_clause) = generics.split_for_impl();
2317        let i = input
2318            .items
2319            .clone()
2320            .into_iter()
2321            .map(|i| match i {
2322                TraitItem::Const(i) => ImplItem::Const({
2323                    let const_token = i.const_token;
2324                    let ident = i.ident;
2325                    let colon_token = i.colon_token;
2326                    let ty = i.ty;
2327                    let semi_token = i.semi_token;
2328                    parse_quote! {
2329                        #const_token
2330                        #ident
2331                        #colon_token
2332                        #ty
2333                        =
2334                        <__T as #name #ty_generics>::#ident
2335                        #semi_token
2336                    }
2337                }),
2338                TraitItem::Fn(i) => ImplItem::Fn({
2339                    let mut sig = i.sig;
2340                    let ident = sig.ident.clone();
2341                    let args = sig
2342                        .inputs
2343                        .iter_mut()
2344                        .enumerate()
2345                        .map(|(n, i)| match i {
2346                            FnArg::Receiver(receiver) => {
2347                                let reference = receiver.reference.as_ref().map(|(and, _)| and);
2348                                let mutability = receiver.mutability.as_ref();
2349                                let ident = &receiver.self_token;
2350                                quote!(#reference #mutability *#ident)
2351                            }
2352                            FnArg::Typed(pat_type) => {
2353                                let ident = Ident::new(&format!("arg{n}"), pat_type.span());
2354                                *pat_type.pat = parse_quote!(#ident);
2355                                quote!(#ident)
2356                            }
2357                        })
2358                        .collect::<Vec<_>>();
2359                    parse_quote! {
2360                        #sig
2361                        {
2362                            <__T as #name #ty_generics>::#ident(
2363                                #(#args),*
2364                            )
2365                        }
2366                    }
2367                }),
2368                TraitItem::Type(i) => ImplItem::Type({
2369                    let type_token = i.type_token;
2370                    let ident = i.ident;
2371                    let semi_token = i.semi_token;
2372                    parse_quote! {
2373                        #type_token
2374                        #ident
2375                        =
2376                        <__T as #name #ty_generics>::#ident
2377                        #semi_token
2378                    }
2379                }),
2380                _ => unimplemented!("unknown/unsupported item"),
2381            })
2382            .collect::<Vec<_>>();
2383        let extra = extra.into_iter().map(|(k, _)| k);
2384        derived.push(quote! {
2385            impl #impl_generics #name #ty_generics for ::object_rainbow::#path<
2386                __T,
2387                #(#extra),*
2388            >
2389            #where_clause
2390            {
2391                #(#i)*
2392            }
2393        });
2394    }
2395    let output = quote! {
2396        #input
2397
2398        #(#derived)*
2399    };
2400    output.into()
2401}