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, Field, FnArg, GenericParam, Generics, Ident,
10    ImplItem, ItemTrait, LitStr, Path, TraitItem, Type, TypeGenerics, parse::Parse,
11    parse_macro_input, 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 mut defs = Vec::new();
465    let generics =
466        match bounds_topological(input.generics, &input.data, &input.attrs, &name, &mut defs) {
467            Ok(g) => g,
468            Err(e) => return e.into_compile_error().into(),
469        };
470    let traverse = gen_traverse(&input.data, &ty_generics);
471    let (impl_generics, _, where_clause) = generics.split_for_impl();
472    let target = parse_for(&name, &input.attrs);
473    let output = quote! {
474        const _: () = {
475            #(#defs)*
476
477            #[automatically_derived]
478            impl #impl_generics ::object_rainbow::Topological for #target #ty_generics
479            #where_clause
480            {
481                fn traverse(&self, visitor: &mut impl ::object_rainbow::PointVisitor) {
482                    #traverse
483                }
484            }
485        };
486    };
487    TokenStream::from(output)
488}
489
490#[derive(Debug, FromMeta)]
491#[darling(derive_syn_parse)]
492struct ContainerTopologyArgs {
493    #[darling(default)]
494    recursive: bool,
495    #[darling(default)]
496    inline: bool,
497}
498
499fn parse_recursive_inline(attrs: &[Attribute]) -> syn::Result<(bool, bool)> {
500    let mut r = false;
501    let mut i = false;
502    for attr in attrs {
503        if attr_str(attr).as_deref() == Some("topology") {
504            let ContainerTopologyArgs { recursive, inline } = attr.parse_args()?;
505            if recursive {
506                r = true;
507            }
508            if inline {
509                i = true;
510            }
511        }
512    }
513    Ok((r, i))
514}
515
516#[derive(Debug, FromMeta)]
517#[darling(derive_syn_parse)]
518struct FieldTopologyArgs {
519    bound: Option<Path>,
520    #[darling(default)]
521    unchecked: bool,
522    with: Option<Expr>,
523    #[darling(default, rename = "unstable_mutual")]
524    mutual: bool,
525}
526
527fn bounds_topological(
528    mut generics: Generics,
529    data: &Data,
530    attrs: &[Attribute],
531    name: &Ident,
532    defs: &mut Vec<proc_macro2::TokenStream>,
533) -> syn::Result<Generics> {
534    let (recursive, inline) = parse_recursive_inline(attrs)?;
535    let g = &bounds_g(&generics);
536    let g_clone = generics.clone();
537    let (impl_generics, ty_generics, where_clause) = g_clone.split_for_impl();
538    let this = quote_spanned! { name.span() =>
539        #name #ty_generics
540    };
541    let bound = if recursive {
542        quote! { ::object_rainbow::Traversible }
543    } else {
544        quote! { ::object_rainbow::Topological }
545    };
546    match data {
547        Data::Struct(data) => {
548            'field: for f in data.fields.iter() {
549                let ty = &f.ty;
550                let mut b = None;
551                for attr in &f.attrs {
552                    if attr_str(attr).as_deref() == Some("topology") {
553                        let FieldTopologyArgs {
554                            bound,
555                            unchecked,
556                            mutual,
557                            ..
558                        } = attr.parse_args()?;
559                        if mutual {
560                            let conditional =
561                                format!("__ConditionalTopology_{}", f.ident.as_ref().unwrap());
562                            let conditional = Ident::new(&conditional, f.span());
563                            defs.push(quote! {
564                                #[allow(non_camel_case_types)]
565                                trait #conditional #impl_generics #where_clause {
566                                    fn traverse(
567                                        &self, visitor: &mut impl ::object_rainbow::PointVisitor,
568                                    ) where #this: ::object_rainbow::Traversible;
569                                }
570
571                                impl #impl_generics #conditional #ty_generics for #ty
572                                #where_clause
573                                {
574                                    fn traverse(
575                                        &self, visitor: &mut impl ::object_rainbow::PointVisitor,
576                                    ) where #this: ::object_rainbow::Traversible {
577                                        ::object_rainbow::Topological::traverse(self, visitor)
578                                    }
579                                }
580                            });
581                            b = Some(parse_quote!(#conditional #ty_generics));
582                        }
583                        if unchecked {
584                            continue 'field;
585                        }
586                        if let Some(bound) = bound {
587                            b = Some(bound);
588                        }
589                    }
590                }
591                let bound = if let Some(bound) = b {
592                    quote! { #bound }
593                } else {
594                    bound.clone()
595                };
596                if type_contains_generics(GContext { g, always: false }, ty) {
597                    generics.make_where_clause().predicates.push(
598                        parse_quote_spanned! { ty.span() =>
599                            #ty: #bound
600                        },
601                    );
602                }
603            }
604        }
605        Data::Enum(data) => {
606            for v in data.variants.iter() {
607                'field: for (i, f) in v.fields.iter().enumerate() {
608                    let ty = &f.ty;
609                    let mut b = None;
610                    for attr in &f.attrs {
611                        if attr_str(attr).as_deref() == Some("topology") {
612                            let FieldTopologyArgs {
613                                bound,
614                                unchecked,
615                                mutual,
616                                ..
617                            } = attr.parse_args()?;
618                            if mutual {
619                                let conditional = format!("__ConditionalTopology_{i}");
620                                let conditional = Ident::new(&conditional, f.span());
621                                defs.push(quote! {
622                                #[allow(non_camel_case_types)]
623                                trait #conditional #impl_generics #where_clause {
624                                    fn traverse(
625                                        &self, visitor: &mut impl ::object_rainbow::PointVisitor,
626                                    ) where #this: ::object_rainbow::Traversible;
627                                }
628
629                                impl #impl_generics #conditional #ty_generics for #ty
630                                #where_clause
631                                {
632                                    fn traverse(
633                                        &self, visitor: &mut impl ::object_rainbow::PointVisitor,
634                                    ) where #this: ::object_rainbow::Traversible {
635                                        ::object_rainbow::Topological::traverse(self, visitor)
636                                    }
637                                }
638                            });
639                            }
640                            if unchecked {
641                                continue 'field;
642                            }
643                            if let Some(bound) = bound {
644                                b = Some(bound);
645                            }
646                        }
647                    }
648                    let bound = if let Some(bound) = b {
649                        quote! { #bound }
650                    } else {
651                        bound.clone()
652                    };
653                    if type_contains_generics(GContext { g, always: false }, ty) {
654                        generics.make_where_clause().predicates.push(
655                            parse_quote_spanned! { ty.span() =>
656                                #ty: #bound
657                            },
658                        );
659                    }
660                }
661            }
662        }
663        Data::Union(data) => {
664            return Err(Error::new_spanned(
665                data.union_token,
666                "`union`s are not supported",
667            ));
668        }
669    }
670    let output_bound = if inline {
671        quote! {
672            ::object_rainbow::InlineOutput
673        }
674    } else {
675        quote! {
676            ::object_rainbow::ToOutput
677        }
678    };
679    if recursive {
680        generics
681            .make_where_clause()
682            .predicates
683            .push(parse_quote_spanned! { name.span() =>
684                Self: #output_bound + ::object_rainbow::Tagged
685            });
686    }
687    Ok(generics)
688}
689
690fn fields_traverse(
691    fields: &syn::Fields,
692    ty_generics: &TypeGenerics<'_>,
693) -> proc_macro2::TokenStream {
694    match fields {
695        syn::Fields::Named(fields) => {
696            let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
697            let traverse = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
698                let ty = &f.ty;
699                let mut w = None;
700                let mut b = None;
701                for attr in &f.attrs {
702                    if attr_str(attr).as_deref() == Some("topology") {
703                        let FieldTopologyArgs {
704                            with,
705                            bound,
706                            mutual,
707                            ..
708                        } = match attr.parse_args() {
709                            Ok(args) => args,
710                            Err(e) => return e.into_compile_error(),
711                        };
712                        if mutual {
713                            let conditional = format!("__ConditionalTopology_{i}");
714                            let conditional = Ident::new(&conditional, f.span());
715                            w = Some(parse_quote!(traverse));
716                            b = Some(parse_quote!(#conditional #ty_generics));
717                        }
718                        if let Some(with) = with {
719                            w = Some(with);
720                        }
721                        if let Some(bound) = bound {
722                            b = Some(bound);
723                        }
724                    }
725                }
726                if let Some(with) = w {
727                    if let Some(bound) = b {
728                        quote_spanned! { f.ty.span() =>
729                            <#ty as #bound>::#with(#i, visitor)
730                        }
731                    } else {
732                        quote_spanned! { f.ty.span() =>
733                            #with(#i, visitor)
734                        }
735                    }
736                } else {
737                    quote_spanned! { f.ty.span() =>
738                        #i.traverse(visitor)
739                    }
740                }
741            });
742            quote! {
743                { #(#let_self),* } => {
744                    #(#traverse);*
745                }
746            }
747        }
748        syn::Fields::Unnamed(fields) => {
749            let let_self = fields
750                .unnamed
751                .iter()
752                .enumerate()
753                .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
754            let traverse = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
755                let ty = &f.ty;
756                let mut w = None;
757                let mut b = None;
758                for attr in &f.attrs {
759                    if attr_str(attr).as_deref() == Some("topology") {
760                        let FieldTopologyArgs {
761                            with,
762                            bound,
763                            mutual,
764                            ..
765                        } = match attr.parse_args() {
766                            Ok(args) => args,
767                            Err(e) => return e.into_compile_error(),
768                        };
769                        if mutual {
770                            let conditional = format!("__ConditionalTopology_{i}");
771                            let conditional = Ident::new(&conditional, f.span());
772                            w = Some(parse_quote!(traverse));
773                            b = Some(parse_quote!(#conditional #ty_generics));
774                        }
775                        if let Some(with) = with {
776                            w = Some(with);
777                        }
778                        if let Some(bound) = bound {
779                            b = Some(bound);
780                        }
781                    }
782                }
783                if let Some(with) = w {
784                    if let Some(bound) = b {
785                        quote_spanned! { f.ty.span() =>
786                            <#ty as #bound>::#with(#i, visitor)
787                        }
788                    } else {
789                        quote_spanned! { f.ty.span() =>
790                            #with(#i, visitor)
791                        }
792                    }
793                } else {
794                    quote_spanned! { f.ty.span() =>
795                        #i.traverse(visitor)
796                    }
797                }
798            });
799            quote! {
800                (#(#let_self),*) => {
801                    #(#traverse);*
802                }
803            }
804        }
805        syn::Fields::Unit => quote! {
806            => {}
807        },
808    }
809}
810
811fn gen_traverse(data: &Data, ty_generics: &TypeGenerics<'_>) -> proc_macro2::TokenStream {
812    match data {
813        Data::Struct(data) => {
814            let arm = fields_traverse(&data.fields, ty_generics);
815            quote! {
816                match self {
817                    Self #arm
818                }
819            }
820        }
821        Data::Enum(data) => {
822            let to_output = data.variants.iter().map(|v| {
823                let ident = &v.ident;
824                let arm = fields_traverse(&v.fields, ty_generics);
825                quote! { Self::#ident #arm }
826            });
827            quote! {
828                let kind = ::object_rainbow::Enum::kind(self);
829                let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
830                tag.traverse(visitor);
831                match self {
832                    #(#to_output)*
833                }
834            }
835        }
836        Data::Union(data) => {
837            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
838        }
839    }
840}
841
842/// ```rust
843/// use object_rainbow::Tagged;
844///
845/// #[derive(Tagged)]
846/// struct Three<A, B, C> {
847///     a: A,
848///     #[tags(skip)]
849///     b: B,
850///     c: C,
851/// }
852///
853/// object_rainbow::assert_impl!(
854///     impl<A, B, C> Tagged for Three<A, B, C>
855///     where
856///         A: Tagged,
857///         C: Tagged,
858///     {}
859/// );
860/// ```
861#[proc_macro_derive(Tagged, attributes(tags))]
862pub fn derive_tagged(input: TokenStream) -> TokenStream {
863    let input = parse_macro_input!(input as DeriveInput);
864    let name = input.ident;
865    let mut errors = Vec::new();
866    let generics = match bounds_tagged(input.generics, &input.data, &mut errors) {
867        Ok(g) => g,
868        Err(e) => return e.into_compile_error().into(),
869    };
870    let tags = gen_tags(&input.data, &input.attrs, &mut errors);
871    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
872    let errors = errors.into_iter().map(|e| e.into_compile_error());
873    let target = parse_for(&name, &input.attrs);
874    let output = quote! {
875        #(#errors)*
876
877        #[automatically_derived]
878        impl #impl_generics ::object_rainbow::Tagged for #target #ty_generics #where_clause {
879            const TAGS: ::object_rainbow::Tags = #tags;
880        }
881    };
882    TokenStream::from(output)
883}
884
885struct FieldTagArgs {
886    skip: bool,
887}
888
889impl Parse for FieldTagArgs {
890    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
891        let mut skip = false;
892        while !input.is_empty() {
893            let ident = input.parse::<Ident>()?;
894            if ident.to_string().as_str() != "skip" {
895                return Err(Error::new(ident.span(), "expected: skip"));
896            }
897            skip = true;
898            if !input.is_empty() {
899                input.parse::<Comma>()?;
900            }
901        }
902        Ok(Self { skip })
903    }
904}
905
906fn bounds_tagged(
907    mut generics: Generics,
908    data: &Data,
909    errors: &mut Vec<Error>,
910) -> syn::Result<Generics> {
911    let g = &bounds_g(&generics);
912    match data {
913        Data::Struct(data) => {
914            for f in data.fields.iter() {
915                let mut skip = false;
916                for attr in &f.attrs {
917                    if attr_str(attr).as_deref() == Some("tags") {
918                        match attr.parse_args::<FieldTagArgs>() {
919                            Ok(args) => skip |= args.skip,
920                            Err(e) => errors.push(e),
921                        }
922                    }
923                }
924                if !skip {
925                    let ty = &f.ty;
926                    if type_contains_generics(GContext { g, always: false }, ty) {
927                        generics.make_where_clause().predicates.push(
928                            parse_quote_spanned! { ty.span() =>
929                                #ty: ::object_rainbow::Tagged
930                            },
931                        );
932                    }
933                }
934            }
935        }
936        Data::Enum(data) => {
937            for v in data.variants.iter() {
938                for f in v.fields.iter() {
939                    let mut skip = false;
940                    for attr in &f.attrs {
941                        if attr_str(attr).as_deref() == Some("tags") {
942                            match attr.parse_args::<FieldTagArgs>() {
943                                Ok(args) => skip |= args.skip,
944                                Err(e) => errors.push(e),
945                            }
946                        }
947                    }
948                    if !skip {
949                        let ty = &f.ty;
950                        if type_contains_generics(GContext { g, always: false }, ty) {
951                            generics.make_where_clause().predicates.push(
952                                parse_quote_spanned! { ty.span() =>
953                                    #ty: ::object_rainbow::Tagged
954                                },
955                            );
956                        }
957                    }
958                }
959            }
960        }
961        Data::Union(data) => {
962            return Err(Error::new_spanned(
963                data.union_token,
964                "`union`s are not supported",
965            ));
966        }
967    }
968    Ok(generics)
969}
970
971struct StructTagArgs {
972    tags: Vec<LitStr>,
973}
974
975impl Parse for StructTagArgs {
976    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
977        let mut tags = Vec::new();
978        while !input.is_empty() {
979            let tag = input.parse::<LitStr>()?;
980            tags.push(tag);
981            if !input.is_empty() {
982                input.parse::<Comma>()?;
983            }
984        }
985        Ok(Self { tags })
986    }
987}
988
989fn fields_tags(fields: &syn::Fields) -> Vec<proc_macro2::TokenStream> {
990    fields
991        .iter()
992        .filter_map(|f| {
993            let mut skip = false;
994            for attr in &f.attrs {
995                if attr_str(attr).as_deref() == Some("tags") {
996                    skip |= attr.parse_args::<FieldTagArgs>().ok()?.skip;
997                }
998            }
999            let ty = &f.ty;
1000            (!skip).then_some(quote! { <#ty as ::object_rainbow::Tagged>::TAGS })
1001        })
1002        .collect()
1003}
1004
1005fn gen_tags(data: &Data, attrs: &[Attribute], errors: &mut Vec<Error>) -> proc_macro2::TokenStream {
1006    match data {
1007        Data::Struct(data) => {
1008            let mut tags = Vec::new();
1009            for attr in attrs {
1010                if attr_str(attr).as_deref() == Some("tags") {
1011                    match attr.parse_args::<StructTagArgs>() {
1012                        Ok(mut args) => tags.append(&mut args.tags),
1013                        Err(e) => errors.push(e),
1014                    }
1015                }
1016            }
1017            let nested = fields_tags(&data.fields);
1018            if nested.len() == 1 && tags.is_empty() {
1019                let nested = nested.into_iter().next().unwrap();
1020                quote! {
1021                    #nested
1022                }
1023            } else {
1024                quote! {
1025                    ::object_rainbow::Tags(&[#(#tags),*], &[#(&#nested),*])
1026                }
1027            }
1028        }
1029        Data::Enum(data) => {
1030            let mut tags = Vec::new();
1031            for attr in attrs {
1032                if attr_str(attr).as_deref() == Some("tags") {
1033                    match attr.parse_args::<StructTagArgs>() {
1034                        Ok(mut args) => tags.append(&mut args.tags),
1035                        Err(e) => errors.push(e),
1036                    }
1037                }
1038            }
1039            let mut nested: Vec<_> = data
1040                .variants
1041                .iter()
1042                .flat_map(|v| fields_tags(&v.fields))
1043                .collect();
1044            let kind_tags = quote! {
1045                <
1046                    <
1047                        <
1048                            Self
1049                            as
1050                            ::object_rainbow::Enum
1051                        >::Kind
1052                        as
1053                        ::object_rainbow::enumkind::EnumKind
1054                    >::Tag
1055                    as  ::object_rainbow::Tagged
1056                >::TAGS
1057            };
1058            nested.insert(0, kind_tags);
1059            if nested.len() == 1 && tags.is_empty() {
1060                let nested = nested.into_iter().next().unwrap();
1061                quote! {
1062                    #nested
1063                }
1064            } else {
1065                quote! {
1066                    ::object_rainbow::Tags(&[#(#tags),*], &[#(&#nested),*])
1067                }
1068            }
1069        }
1070        Data::Union(data) => {
1071            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1072        }
1073    }
1074}
1075
1076/// ```rust
1077/// use object_rainbow::Size;
1078///
1079/// #[derive(Size)]
1080/// struct Three<A, B, C> {
1081///     a: A,
1082///     b: B,
1083///     c: C,
1084/// }
1085///
1086/// object_rainbow::assert_impl!(
1087///     impl<A, B, C> Size for Three<A, B, C>
1088///     where
1089///         A: Size<Size = typenum::U2>,
1090///         B: Size<Size = typenum::U3>,
1091///         C: Size<Size = typenum::U7>,
1092///     {}
1093/// );
1094///
1095/// assert_eq!(Three::<[u8; 2], [u8; 3], [u8; 7]>::SIZE, 12);
1096/// ```
1097#[proc_macro_derive(Size)]
1098pub fn derive_size(input: TokenStream) -> TokenStream {
1099    let input = parse_macro_input!(input as DeriveInput);
1100    let name = input.ident;
1101    let size_arr = gen_size_arr(&input.data);
1102    let size = gen_size(&input.data);
1103    let (generics, is_enum) = match bounds_size(input.generics.clone(), &input.data, &size_arr) {
1104        Ok(g) => g,
1105        Err(e) => return e.into_compile_error().into(),
1106    };
1107    let (_, ty_generics, where_clause) = generics.split_for_impl();
1108    let mut generics = input.generics;
1109    if is_enum {
1110        generics.params.push(parse_quote!(
1111            __Output: ::object_rainbow::typenum::Unsigned
1112        ));
1113    }
1114    let (impl_generics, _, _) = generics.split_for_impl();
1115    let target = parse_for(&name, &input.attrs);
1116    let output = quote! {
1117        const _: () = {
1118            use ::object_rainbow::typenum::tarr;
1119
1120            #[automatically_derived]
1121            impl #impl_generics ::object_rainbow::Size for #target #ty_generics #where_clause {
1122                const SIZE: usize = #size;
1123
1124                type Size = <#size_arr as ::object_rainbow::typenum::FoldAdd>::Output;
1125            }
1126        };
1127    };
1128    TokenStream::from(output)
1129}
1130
1131fn bounds_size(
1132    mut generics: Generics,
1133    data: &Data,
1134    size_arr: &proc_macro2::TokenStream,
1135) -> syn::Result<(Generics, bool)> {
1136    let g = &bounds_g(&generics);
1137    let is_enum = match data {
1138        Data::Struct(data) => {
1139            for f in data.fields.iter() {
1140                let ty = &f.ty;
1141                if type_contains_generics(GContext { g, always: false }, ty) {
1142                    generics.make_where_clause().predicates.push(
1143                        parse_quote_spanned! { ty.span() =>
1144                            #ty: ::object_rainbow::Size
1145                        },
1146                    );
1147                }
1148            }
1149            generics.make_where_clause().predicates.push(parse_quote!(
1150                #size_arr: ::object_rainbow::typenum::FoldAdd<
1151                    Output: ::object_rainbow::typenum::Unsigned
1152                >
1153            ));
1154            false
1155        }
1156        Data::Enum(data) => {
1157            for v in data.variants.iter() {
1158                for f in v.fields.iter() {
1159                    let ty = &f.ty;
1160                    if type_contains_generics(GContext { g, always: false }, ty) {
1161                        generics.make_where_clause().predicates.push(
1162                            parse_quote_spanned! { ty.span() =>
1163                                #ty: ::object_rainbow::Size
1164                            },
1165                        );
1166                    }
1167                }
1168            }
1169            for v in data.variants.iter().skip(1) {
1170                let arr = fields_size_arr(&v.fields, true);
1171                generics.make_where_clause().predicates.push(parse_quote!(
1172                    #arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
1173                ));
1174            }
1175            generics.make_where_clause().predicates.push(parse_quote!(
1176                #size_arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
1177            ));
1178            true
1179        }
1180        Data::Union(data) => {
1181            return Err(Error::new_spanned(
1182                data.union_token,
1183                "`union`s are not supported",
1184            ));
1185        }
1186    };
1187    Ok((generics, is_enum))
1188}
1189
1190fn fields_size_arr(fields: &syn::Fields, as_enum: bool) -> proc_macro2::TokenStream {
1191    let kind_size = quote! {
1192        <
1193            <
1194                <
1195                    Self
1196                    as
1197                    ::object_rainbow::Enum
1198                >::Kind
1199                as
1200                ::object_rainbow::enumkind::EnumKind
1201            >::Tag
1202            as  ::object_rainbow::Size
1203        >::Size
1204    };
1205    if fields.is_empty() {
1206        return if as_enum {
1207            quote! { tarr![#kind_size, ::object_rainbow::typenum::consts::U0] }
1208        } else {
1209            quote! { tarr![::object_rainbow::typenum::consts::U0] }
1210        };
1211    }
1212    let size_arr = fields.iter().map(|f| {
1213        let ty = &f.ty;
1214        quote! { <#ty as ::object_rainbow::Size>::Size }
1215    });
1216    if as_enum {
1217        quote! { tarr![#kind_size, ::object_rainbow::typenum::consts::U0, #(#size_arr),*] }
1218    } else {
1219        quote! { tarr![::object_rainbow::typenum::consts::U0, #(#size_arr),*] }
1220    }
1221}
1222
1223fn gen_size_arr(data: &Data) -> proc_macro2::TokenStream {
1224    match data {
1225        Data::Struct(data) => fields_size_arr(&data.fields, false),
1226        Data::Enum(data) => {
1227            if let Some(v) = data.variants.first() {
1228                fields_size_arr(&v.fields, true)
1229            } else {
1230                Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
1231                    .into_compile_error()
1232            }
1233        }
1234        Data::Union(data) => {
1235            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1236        }
1237    }
1238}
1239
1240fn fields_size(fields: &syn::Fields) -> proc_macro2::TokenStream {
1241    if fields.is_empty() {
1242        return quote! {0};
1243    }
1244    let size = fields.iter().map(|f| {
1245        let ty = &f.ty;
1246        quote! { <#ty as ::object_rainbow::Size>::SIZE }
1247    });
1248    quote! {
1249        #(#size)+*
1250    }
1251}
1252
1253fn gen_size(data: &Data) -> proc_macro2::TokenStream {
1254    match data {
1255        Data::Struct(data) => fields_size(&data.fields),
1256        Data::Enum(data) => {
1257            if let Some(v) = data.variants.first() {
1258                let size = fields_size(&v.fields);
1259                let kind_size = quote! {
1260                    <
1261                        <
1262                            <
1263                                Self
1264                                as
1265                                ::object_rainbow::Enum
1266                            >::Kind
1267                            as
1268                            ::object_rainbow::enumkind::EnumKind
1269                        >::Tag
1270                        as  ::object_rainbow::Size
1271                    >::SIZE
1272                };
1273                quote! { #kind_size + #size }
1274            } else {
1275                Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
1276                    .into_compile_error()
1277            }
1278        }
1279        Data::Union(data) => {
1280            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1281        }
1282    }
1283}
1284
1285/// ```rust
1286/// use object_rainbow::{Parse, ParseInline, ParseInput};
1287///
1288/// #[derive(Parse)]
1289/// struct Three<A, B, C> {
1290///     a: A,
1291///     b: B,
1292///     c: C,
1293/// }
1294///
1295/// object_rainbow::assert_impl!(
1296///     impl<A, B, C, I> Parse<I> for Three<A, B, C>
1297///     where
1298///         A: ParseInline<I>,
1299///         B: ParseInline<I>,
1300///         C: Parse<I>,
1301///         I: ParseInput,
1302///     {}
1303/// );
1304/// ```
1305#[proc_macro_derive(Parse, attributes(parse))]
1306pub fn derive_parse(input: TokenStream) -> TokenStream {
1307    let input = parse_macro_input!(input as DeriveInput);
1308    let name = input.ident;
1309    let generics = input.generics.clone();
1310    let (_, ty_generics, _) = generics.split_for_impl();
1311    let mut defs = Vec::new();
1312    let generics = match bounds_parse(input.generics, &input.data, &input.attrs, &name, &mut defs) {
1313        Ok(g) => g,
1314        Err(e) => return e.into_compile_error().into(),
1315    };
1316    let (parse, enum_parse) = gen_parse(&input.data, &ty_generics);
1317    let (impl_generics, _, where_clause) = generics.split_for_impl();
1318    let target = parse_for(&name, &input.attrs);
1319    let enum_parse = enum_parse.map(|enum_parse| {
1320        quote! {
1321            #[automatically_derived]
1322            impl #impl_generics ::object_rainbow::enumkind::EnumParse<__I> for #target #ty_generics
1323            #where_clause
1324            {
1325                fn enum_parse(
1326                    kind: <Self as ::object_rainbow::Enum>::Kind, mut input: __I,
1327                ) -> ::object_rainbow::Result<Self> {
1328                    #enum_parse
1329                }
1330            }
1331        }
1332    });
1333    let output = quote! {
1334        const _: () = {
1335            #(#defs)*
1336
1337            #[automatically_derived]
1338            impl #impl_generics ::object_rainbow::Parse<__I> for #target #ty_generics
1339            #where_clause
1340            {
1341                fn parse(mut input: __I) -> ::object_rainbow::Result<Self> {
1342                    #parse
1343                }
1344            }
1345
1346            #enum_parse
1347        };
1348    };
1349    TokenStream::from(output)
1350}
1351
1352#[derive(Debug, FromMeta)]
1353#[darling(derive_syn_parse)]
1354struct ParseArgs {
1355    bound: Option<Type>,
1356    #[darling(default)]
1357    unchecked: bool,
1358    with: Option<Expr>,
1359    #[darling(default, rename = "unstable_mutual")]
1360    mutual: bool,
1361}
1362
1363fn conditional_parse_name(f: &Field, inline: bool) -> Ident {
1364    let infix = if inline { "ParseInline" } else { "Parse" };
1365    let conditional = format!("__Conditional{infix}_{}", f.ident.as_ref().unwrap());
1366    Ident::new(&conditional, f.span())
1367}
1368
1369fn conditional_parse_input(inline: bool) -> proc_macro2::TokenStream {
1370    if inline {
1371        quote!(&mut impl ::object_rainbow::PointInput<Extra = Self::E>)
1372    } else {
1373        quote!(impl ::object_rainbow::PointInput<Extra = Self::E>)
1374    }
1375}
1376
1377fn conditional_parse_method(inline: bool) -> proc_macro2::TokenStream {
1378    if inline {
1379        quote!(parse_inline)
1380    } else {
1381        quote!(parse)
1382    }
1383}
1384
1385fn bounds_parse(
1386    mut generics: Generics,
1387    data: &Data,
1388    attrs: &[Attribute],
1389    name: &Ident,
1390    defs: &mut Vec<proc_macro2::TokenStream>,
1391) -> syn::Result<Generics> {
1392    let g_clone = generics.clone();
1393    let (impl_generics, ty_generics, where_clause) = g_clone.split_for_impl();
1394    let this = quote_spanned! { name.span() =>
1395        #name #ty_generics
1396    };
1397    let (recursive, _) = parse_recursive_inline(attrs)?;
1398    let tr = |last| match (last, recursive) {
1399        (true, true) => {
1400            quote!(::object_rainbow::Parse<__I> + ::object_rainbow::Object<__I::Extra>)
1401        }
1402        (true, false) => quote!(::object_rainbow::Parse<__I>),
1403        (false, true) => {
1404            quote!(::object_rainbow::ParseInline<__I> + ::object_rainbow::Inline<__I::Extra>)
1405        }
1406        (false, false) => quote!(::object_rainbow::ParseInline<__I>),
1407    };
1408    match data {
1409        Data::Struct(data) => {
1410            let last_at = data.fields.len().saturating_sub(1);
1411            'field: for (i, f) in data.fields.iter().enumerate() {
1412                let last = i == last_at;
1413                let ty = &f.ty;
1414                let mut b = None;
1415                for attr in &f.attrs {
1416                    if attr_str(attr).as_deref() == Some("parse") {
1417                        let ParseArgs {
1418                            bound,
1419                            unchecked,
1420                            mutual,
1421                            ..
1422                        } = attr.parse_args::<ParseArgs>()?;
1423                        if mutual {
1424                            let conditional = conditional_parse_name(f, !last);
1425                            let mut g_clone = g_clone.clone();
1426                            g_clone.params.push(parse_quote!(
1427                                __E: ::core::marker::Send + ::core::marker::Sync
1428                            ));
1429                            let (impl_generics_extra, _, _) = g_clone.split_for_impl();
1430                            let input_type = conditional_parse_input(!last);
1431                            let parse_method = conditional_parse_method(!last);
1432                            defs.push(quote! {
1433                                #[allow(non_camel_case_types)]
1434                                trait #conditional #impl_generics: ::object_rainbow::BoundPair
1435                                #where_clause
1436                                {
1437                                    fn parse(
1438                                        input: #input_type,
1439                                    ) -> ::object_rainbow::Result<Self::T>
1440                                    where #this: ::object_rainbow::Object<Self::E>;
1441                                }
1442
1443                                impl #impl_generics_extra #conditional #ty_generics
1444                                    for (#ty, __E)
1445                                #where_clause
1446                                {
1447                                    fn parse(
1448                                        input: #input_type,
1449                                    ) -> ::object_rainbow::Result<Self::T>
1450                                    where #this: ::object_rainbow::Object<Self::E> {
1451                                        input.#parse_method::<Self::T>()
1452                                    }
1453                                }
1454                            });
1455                            b = Some(parse_quote!(#conditional #ty_generics));
1456                        }
1457                        if unchecked {
1458                            continue 'field;
1459                        }
1460                        if let Some(bound) = bound {
1461                            b = Some(bound);
1462                        }
1463                    }
1464                }
1465                if let Some(bound) = b {
1466                    generics.make_where_clause().predicates.push(
1467                        parse_quote_spanned! { ty.span() =>
1468                            (#ty, __I::Extra): ::object_rainbow::BoundPair<
1469                                T = #ty, E = __I::Extra
1470                            > + #bound
1471                        },
1472                    );
1473                } else {
1474                    let tr = tr(last);
1475                    generics.make_where_clause().predicates.push(
1476                        parse_quote_spanned! { ty.span() =>
1477                            #ty: #tr
1478                        },
1479                    );
1480                }
1481            }
1482        }
1483        Data::Enum(data) => {
1484            for v in data.variants.iter() {
1485                let last_at = v.fields.len().saturating_sub(1);
1486                'field: for (i, f) in v.fields.iter().enumerate() {
1487                    let ty = &f.ty;
1488                    let mut b = None;
1489                    for attr in &f.attrs {
1490                        if attr_str(attr).as_deref() == Some("parse") {
1491                            let ParseArgs {
1492                                bound, unchecked, ..
1493                            } = attr.parse_args::<ParseArgs>()?;
1494                            if unchecked {
1495                                continue 'field;
1496                            }
1497                            if let Some(bound) = bound {
1498                                b = Some(bound);
1499                            }
1500                        }
1501                    }
1502                    if let Some(bound) = b {
1503                        generics.make_where_clause().predicates.push(
1504                            parse_quote_spanned! { ty.span() =>
1505                                (#ty, __I::Extra): ::object_rainbow::BoundPair<
1506                                    T = #ty, E = __I::Extra
1507                                > + #bound
1508                            },
1509                        );
1510                    } else {
1511                        let last = i == last_at;
1512                        let tr = tr(last);
1513                        generics.make_where_clause().predicates.push(
1514                            parse_quote_spanned! { ty.span() =>
1515                                #ty: #tr
1516                            },
1517                        );
1518                    }
1519                }
1520            }
1521        }
1522        Data::Union(data) => {
1523            return Err(Error::new_spanned(
1524                data.union_token,
1525                "`union`s are not supported",
1526            ));
1527        }
1528    }
1529    generics.params.push(if recursive {
1530        parse_quote!(__I: ::object_rainbow::PointInput<
1531            Extra: ::core::marker::Send + ::core::marker::Sync + ::core::clone::Clone
1532        >)
1533    } else {
1534        parse_quote!(__I: ::object_rainbow::ParseInput)
1535    });
1536    Ok(generics)
1537}
1538
1539fn gen_parse(
1540    data: &Data,
1541    ty_generics: &TypeGenerics<'_>,
1542) -> (proc_macro2::TokenStream, Option<proc_macro2::TokenStream>) {
1543    match data {
1544        Data::Struct(data) => {
1545            let arm = fields_parse(&data.fields, ty_generics);
1546            (quote! { Ok(Self #arm)}, None)
1547        }
1548        Data::Enum(data) => {
1549            let parse = data.variants.iter().map(|v| {
1550                let ident = &v.ident;
1551                let arm = fields_parse(&v.fields, ty_generics);
1552                quote! {
1553                    <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
1554                }
1555            });
1556            (
1557                quote! {
1558                    ::object_rainbow::enumkind::EnumParse::parse_as_enum(input)
1559                },
1560                Some(quote! {
1561                    Ok(match kind {
1562                        #(#parse)*
1563                    })
1564                }),
1565            )
1566        }
1567        Data::Union(data) => (
1568            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error(),
1569            None,
1570        ),
1571    }
1572}
1573
1574fn fields_parse(fields: &syn::Fields, ty_generics: &TypeGenerics<'_>) -> proc_macro2::TokenStream {
1575    let last_at = fields.len().saturating_sub(1);
1576    match fields {
1577        syn::Fields::Named(fields) => {
1578            let parse = fields.named.iter().enumerate().map(|(i, f)| {
1579                let last = i == last_at;
1580                let ty = &f.ty;
1581                let mut w = None;
1582                let mut b = None;
1583                for attr in &f.attrs {
1584                    if attr_str(attr).as_deref() == Some("parse") {
1585                        let ParseArgs {
1586                            with,
1587                            bound,
1588                            mutual,
1589                            ..
1590                        } = match attr.parse_args::<ParseArgs>() {
1591                            Ok(args) => args,
1592                            Err(e) => return e.into_compile_error(),
1593                        };
1594                        if mutual {
1595                            let conditional = format!(
1596                                "__Conditional{}_{}",
1597                                if last { "Parse" } else { "ParseInline" },
1598                                f.ident.as_ref().unwrap(),
1599                            );
1600                            let conditional = Ident::new(&conditional, f.span());
1601                            w = Some(parse_quote!(parse));
1602                            b = Some(parse_quote!(#conditional #ty_generics));
1603                        }
1604                        if let Some(with) = with {
1605                            w = Some(with);
1606                        }
1607                        if let Some(bound) = bound {
1608                            b = Some(bound);
1609                        }
1610                    }
1611                }
1612                let i = f.ident.as_ref().unwrap();
1613                if let Some(with) = w {
1614                    let arg = if last {
1615                        quote!(input)
1616                    } else {
1617                        quote!(&mut input)
1618                    };
1619                    if let Some(bound) = b {
1620                        quote_spanned! { f.ty.span() =>
1621                            #i: <(#ty, __I::Extra) as #bound>::#with(#arg)?
1622                        }
1623                    } else {
1624                        quote_spanned! { f.ty.span() =>
1625                            #i: #with(#arg)?
1626                        }
1627                    }
1628                } else {
1629                    let method = if last {
1630                        quote!(parse)
1631                    } else {
1632                        quote!(parse_inline)
1633                    };
1634                    quote_spanned! { f.ty.span() =>
1635                        #i: input.#method()?
1636                    }
1637                }
1638            });
1639            quote! { { #(#parse),* } }
1640        }
1641        syn::Fields::Unnamed(fields) => {
1642            let parse = fields.unnamed.iter().enumerate().map(|(i, f)| {
1643                let ty = &f.ty;
1644                let mut w = None;
1645                let mut b = None;
1646                for attr in &f.attrs {
1647                    if attr_str(attr).as_deref() == Some("parse") {
1648                        let ParseArgs { with, bound, .. } = match attr.parse_args::<ParseArgs>() {
1649                            Ok(args) => args,
1650                            Err(e) => return e.into_compile_error(),
1651                        };
1652                        if let Some(with) = with {
1653                            w = Some(with);
1654                        }
1655                        if let Some(bound) = bound {
1656                            b = Some(bound);
1657                        }
1658                    }
1659                }
1660                let last = i == last_at;
1661                if let Some(with) = w {
1662                    let arg = if last {
1663                        quote!(input)
1664                    } else {
1665                        quote!(&mut input)
1666                    };
1667                    if let Some(bound) = b {
1668                        quote_spanned! { f.ty.span() =>
1669                            <(#ty, __I::Extra) as #bound>::#with(#arg)?
1670                        }
1671                    } else {
1672                        quote_spanned! { f.ty.span() =>
1673                            #with(#arg)?
1674                        }
1675                    }
1676                } else {
1677                    let method = if last {
1678                        quote!(parse)
1679                    } else {
1680                        quote!(parse_inline)
1681                    };
1682                    quote_spanned! { f.ty.span() =>
1683                        input.#method()?
1684                    }
1685                }
1686            });
1687            quote! { (#(#parse),*) }
1688        }
1689        syn::Fields::Unit => quote! {},
1690    }
1691}
1692
1693/// ```rust
1694/// use object_rainbow::{Parse, ParseInline, ParseInput};
1695///
1696/// #[derive(Parse, ParseInline)]
1697/// struct Three<A, B, C> {
1698///     a: A,
1699///     b: B,
1700///     c: C,
1701/// }
1702///
1703/// object_rainbow::assert_impl!(
1704///     impl<A, B, C, I> ParseInline<I> for Three<A, B, C>
1705///     where
1706///         A: ParseInline<I>,
1707///         B: ParseInline<I>,
1708///         C: ParseInline<I>,
1709///         I: ParseInput,
1710///     {}
1711/// );
1712/// ```
1713#[proc_macro_derive(ParseInline, attributes(parse))]
1714pub fn derive_parse_inline(input: TokenStream) -> TokenStream {
1715    let input = parse_macro_input!(input as DeriveInput);
1716    let name = input.ident;
1717    let generics = input.generics.clone();
1718    let (_, ty_generics, _) = generics.split_for_impl();
1719    let generics = match bounds_parse_inline(input.generics, &input.data, &input.attrs) {
1720        Ok(g) => g,
1721        Err(e) => return e.into_compile_error().into(),
1722    };
1723    let (parse_inline, enum_parse_inline) = gen_parse_inline(&input.data);
1724    let (impl_generics, _, where_clause) = generics.split_for_impl();
1725    let target = parse_for(&name, &input.attrs);
1726    let enum_parse_inline = enum_parse_inline.map(|enum_parse_inline| {
1727        quote! {
1728            #[automatically_derived]
1729            impl #impl_generics ::object_rainbow::enumkind::EnumParseInline<__I>
1730            for #target #ty_generics #where_clause {
1731                fn enum_parse_inline(
1732                    kind: <Self as ::object_rainbow::Enum>::Kind, input: &mut __I,
1733                ) -> ::object_rainbow::Result<Self> {
1734                    #enum_parse_inline
1735                }
1736            }
1737        }
1738    });
1739    let output = quote! {
1740        #[automatically_derived]
1741        impl #impl_generics ::object_rainbow::ParseInline<__I>
1742        for #target #ty_generics #where_clause {
1743            fn parse_inline(input: &mut __I) -> ::object_rainbow::Result<Self> {
1744                #parse_inline
1745            }
1746        }
1747
1748        #enum_parse_inline
1749    };
1750    TokenStream::from(output)
1751}
1752
1753fn bounds_parse_inline(
1754    mut generics: Generics,
1755    data: &Data,
1756    attrs: &[Attribute],
1757) -> syn::Result<Generics> {
1758    let (recursive, _) = parse_recursive_inline(attrs)?;
1759    let tr = if recursive {
1760        quote!(::object_rainbow::ParseInline<__I> + ::object_rainbow::Inline<__I::Extra>)
1761    } else {
1762        quote!(::object_rainbow::ParseInline<__I>)
1763    };
1764    match data {
1765        Data::Struct(data) => {
1766            'field: for f in data.fields.iter() {
1767                let ty = &f.ty;
1768                let mut b = None;
1769                for attr in &f.attrs {
1770                    if attr_str(attr).as_deref() == Some("parse") {
1771                        let ParseArgs {
1772                            bound, unchecked, ..
1773                        } = attr.parse_args::<ParseArgs>()?;
1774                        if unchecked {
1775                            continue 'field;
1776                        }
1777                        if let Some(bound) = bound {
1778                            b = Some(bound);
1779                        }
1780                    }
1781                }
1782                if let Some(bound) = b {
1783                    generics.make_where_clause().predicates.push(
1784                        parse_quote_spanned! { ty.span() =>
1785                            (#ty, __I::Extra): #bound
1786                        },
1787                    );
1788                } else {
1789                    generics.make_where_clause().predicates.push(
1790                        parse_quote_spanned! { ty.span() =>
1791                            #ty: #tr
1792                        },
1793                    );
1794                }
1795            }
1796        }
1797        Data::Enum(data) => {
1798            for v in data.variants.iter() {
1799                'field: for f in v.fields.iter() {
1800                    let ty = &f.ty;
1801                    let mut b = None;
1802                    for attr in &f.attrs {
1803                        if attr_str(attr).as_deref() == Some("parse") {
1804                            let ParseArgs {
1805                                bound, unchecked, ..
1806                            } = attr.parse_args::<ParseArgs>()?;
1807                            if unchecked {
1808                                continue 'field;
1809                            }
1810                            if let Some(bound) = bound {
1811                                b = Some(bound);
1812                            }
1813                        }
1814                    }
1815                    if let Some(bound) = b {
1816                        generics.make_where_clause().predicates.push(
1817                            parse_quote_spanned! { ty.span() =>
1818                                (#ty, __I::Extra): #bound
1819                            },
1820                        );
1821                    } else {
1822                        generics.make_where_clause().predicates.push(
1823                            parse_quote_spanned! { ty.span() =>
1824                                #ty: #tr
1825                            },
1826                        );
1827                    }
1828                }
1829            }
1830        }
1831        Data::Union(data) => {
1832            return Err(Error::new_spanned(
1833                data.union_token,
1834                "`union`s are not supported",
1835            ));
1836        }
1837    }
1838    generics.params.push(if recursive {
1839        parse_quote!(__I: ::object_rainbow::PointInput<
1840            Extra: ::core::marker::Send + ::core::marker::Sync
1841        >)
1842    } else {
1843        parse_quote!(__I: ::object_rainbow::ParseInput)
1844    });
1845    Ok(generics)
1846}
1847
1848fn fields_parse_inline(fields: &syn::Fields) -> proc_macro2::TokenStream {
1849    match fields {
1850        syn::Fields::Named(fields) => {
1851            let parse = fields.named.iter().map(|f| {
1852                let i = f.ident.as_ref().unwrap();
1853                quote_spanned! { f.ty.span() =>
1854                    #i: input.parse_inline()?
1855                }
1856            });
1857            quote! { { #(#parse),* } }
1858        }
1859        syn::Fields::Unnamed(fields) => {
1860            let parse = fields.unnamed.iter().map(|f| {
1861                quote_spanned! { f.ty.span() =>
1862                    input.parse_inline()?
1863                }
1864            });
1865            quote! { (#(#parse),*) }
1866        }
1867        syn::Fields::Unit => quote! {},
1868    }
1869}
1870
1871fn gen_parse_inline(data: &Data) -> (proc_macro2::TokenStream, Option<proc_macro2::TokenStream>) {
1872    match data {
1873        Data::Struct(data) => {
1874            let arm = fields_parse_inline(&data.fields);
1875            (quote! { Ok(Self #arm) }, None)
1876        }
1877        Data::Enum(data) => {
1878            let parse_inline = data.variants.iter().map(|v| {
1879                let ident = &v.ident;
1880                let arm = fields_parse_inline(&v.fields);
1881                quote! {
1882                    <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
1883                }
1884            });
1885            (
1886                quote! {
1887                    ::object_rainbow::enumkind::EnumParseInline::parse_as_inline_enum(input)
1888                },
1889                Some(quote! {
1890                    Ok(match kind {
1891                        #(#parse_inline)*
1892                    })
1893                }),
1894            )
1895        }
1896        Data::Union(data) => (
1897            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error(),
1898            None,
1899        ),
1900    }
1901}
1902
1903/// ```rust
1904/// use object_rainbow::{Parse, ParseAsInline, ParseInline, ParseInput};
1905///
1906/// #[derive(ParseAsInline)]
1907/// struct Thing<T> {
1908///     inner: T,
1909/// }
1910///
1911/// object_rainbow::assert_impl!(
1912///     impl<T, I> Parse<I> for Thing<T>
1913///     where
1914///         Thing<T>: ParseInline<I>,
1915///         I: ParseInput,
1916///     {}
1917/// );
1918/// ```
1919#[proc_macro_derive(ParseAsInline)]
1920pub fn derive_parse_as_inline(input: TokenStream) -> TokenStream {
1921    let input = parse_macro_input!(input as DeriveInput);
1922    let name = input.ident;
1923    let generics = input.generics.clone();
1924    let (_, ty_generics, _) = generics.split_for_impl();
1925    let generics = match bounds_parse_as_inline(input.generics, &name) {
1926        Ok(g) => g,
1927        Err(e) => return e.into_compile_error().into(),
1928    };
1929    let (impl_generics, _, where_clause) = generics.split_for_impl();
1930    let target = parse_for(&name, &input.attrs);
1931    let output = quote! {
1932        #[automatically_derived]
1933        impl #impl_generics ::object_rainbow::Parse<__I> for #target #ty_generics #where_clause {
1934            fn parse(input: __I) -> ::object_rainbow::Result<Self> {
1935                ::object_rainbow::ParseInline::<__I>::parse_as_inline(input)
1936            }
1937        }
1938    };
1939    TokenStream::from(output)
1940}
1941
1942fn bounds_parse_as_inline(mut generics: Generics, name: &Ident) -> syn::Result<Generics> {
1943    generics
1944        .make_where_clause()
1945        .predicates
1946        .push(parse_quote_spanned! { name.span() =>
1947            Self: ::object_rainbow::ParseInline::<__I>
1948        });
1949    generics
1950        .params
1951        .push(parse_quote!(__I: ::object_rainbow::ParseInput));
1952    Ok(generics)
1953}
1954
1955fn parse_path(attr: &Attribute) -> syn::Result<Type> {
1956    attr.parse_args::<LitStr>()?.parse()
1957}
1958
1959fn attr_str(attr: &Attribute) -> Option<String> {
1960    Some(attr.path().get_ident()?.to_string())
1961}
1962
1963/// ```rust
1964/// use std::num::NonZero;
1965///
1966/// use object_rainbow::{Enum, MaybeHasNiche, ToOutput};
1967///
1968/// #[derive(Enum, ToOutput, MaybeHasNiche)]
1969/// enum WithDefault {
1970///     A(u8),
1971///     B(bool),
1972/// }
1973///
1974/// assert_eq!(Some(WithDefault::A(32)).vec(), [0, 32]);
1975/// assert_eq!(Some(WithDefault::B(true)).vec(), [1, 1]);
1976/// assert_eq!(None::<WithDefault>.vec(), [2, 0]);
1977///
1978/// #[derive(Enum, ToOutput, MaybeHasNiche)]
1979/// #[enumtag("NonZero<u8>")]
1980/// enum WithNz {
1981///     A(u8),
1982///     B(bool),
1983/// }
1984///
1985/// assert_eq!(None::<WithNz>.vec(), [0, 0]);
1986/// assert_eq!(Some(WithNz::A(32)).vec(), [1, 32]);
1987/// assert_eq!(Some(WithNz::B(true)).vec(), [2, 1]);
1988///
1989/// #[derive(Enum, ToOutput, MaybeHasNiche)]
1990/// #[enumtag("bool")]
1991/// enum WithBool {
1992///     A(u8),
1993///     B(bool),
1994/// }
1995///
1996/// assert_eq!(Some(WithBool::A(32)).vec(), [0, 32]);
1997/// assert_eq!(Some(WithBool::B(true)).vec(), [1, 1]);
1998/// assert_eq!(None::<WithBool>.vec(), [2, 0]);
1999///
2000/// #[derive(Enum, ToOutput, MaybeHasNiche)]
2001/// #[enumtag("u8")]
2002/// enum WithU8 {
2003///     A(u8),
2004///     B(bool),
2005/// }
2006///
2007/// assert_eq!(Some(WithU8::A(32)).vec(), [0, 32]);
2008/// assert_eq!(Some(WithU8::B(true)).vec(), [1, 1]);
2009/// assert_eq!(None::<WithU8>.vec(), [1, 2]);
2010///
2011/// #[derive(Enum, ToOutput, MaybeHasNiche)]
2012/// #[enumtag("u8")]
2013/// enum WithoutNiche {
2014///     A(u8),
2015///     B(u8),
2016/// }
2017///
2018/// assert_eq!(Some(WithoutNiche::A(32)).vec(), [0, 0, 32]);
2019/// assert_eq!(Some(WithoutNiche::B(1)).vec(), [0, 1, 1]);
2020/// assert_eq!(None::<WithoutNiche>.vec(), [1]);
2021/// ```
2022#[proc_macro_derive(Enum, attributes(enumtag))]
2023pub fn derive_enum(input: TokenStream) -> TokenStream {
2024    let input = parse_macro_input!(input as DeriveInput);
2025    let name = input.ident;
2026    let generics = input.generics.clone();
2027    let (_, ty_generics, _) = generics.split_for_impl();
2028    let generics = input.generics;
2029    let length = gen_length(&input.data);
2030    let variants = gen_variants(&input.data);
2031    let variant_count = gen_variant_count(&input.data);
2032    let to_tag = gen_to_tag(&input.data);
2033    let from_tag = gen_from_tag(&input.data);
2034    let kind = gen_kind(&input.data);
2035    let (impl_generics, _, where_clause) = generics.split_for_impl();
2036    let mut errors = Vec::new();
2037    let mut enumtag = None;
2038    for attr in &input.attrs {
2039        if attr_str(attr).as_deref() == Some("enumtag") {
2040            match parse_path(attr) {
2041                Ok(path) => {
2042                    if enumtag.is_some() {
2043                        errors.push(Error::new_spanned(path, "duplicate tag"));
2044                    } else {
2045                        enumtag = Some(path);
2046                    }
2047                }
2048                Err(e) => errors.push(e),
2049            }
2050        }
2051    }
2052    let enumtag = enumtag.unwrap_or_else(|| {
2053        parse_quote!(
2054            ::object_rainbow::partial_byte_tag::PartialByteTag<#length>
2055        )
2056    });
2057    let errors = errors.into_iter().map(|e| e.into_compile_error());
2058    let target = parse_for(&name, &input.attrs);
2059    let output = quote! {
2060        const _: () = {
2061            #(#errors)*
2062
2063            use ::object_rainbow::enumkind::EnumKind;
2064
2065            #[derive(Clone, Copy, ::object_rainbow::ParseAsInline)]
2066            pub enum __Kind {
2067                #variants
2068            }
2069
2070            #[automatically_derived]
2071            impl ::object_rainbow::enumkind::EnumKind for __Kind {
2072                type Tag = ::object_rainbow::enumkind::EnumTag<
2073                    #enumtag,
2074                    #variant_count,
2075                >;
2076
2077                fn to_tag(self) -> Self::Tag {
2078                    #to_tag
2079                }
2080
2081                fn from_tag(tag: Self::Tag) -> Self {
2082                    #from_tag
2083                }
2084            }
2085
2086            impl<I: ::object_rainbow::ParseInput> ::object_rainbow::ParseInline<I> for __Kind {
2087                fn parse_inline(input: &mut I) -> ::object_rainbow::Result<Self> {
2088                    Ok(::object_rainbow::enumkind::EnumKind::from_tag(input.parse_inline()?))
2089                }
2090            }
2091
2092            #[automatically_derived]
2093            impl #impl_generics ::object_rainbow::Enum for #target #ty_generics #where_clause {
2094                type Kind = __Kind;
2095
2096                fn kind(&self) -> Self::Kind {
2097                    #kind
2098                }
2099            }
2100        };
2101    };
2102    TokenStream::from(output)
2103}
2104
2105fn gen_length(data: &Data) -> proc_macro2::TokenStream {
2106    match data {
2107        Data::Struct(data) => {
2108            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2109        }
2110        Data::Enum(data) => {
2111            let name = format!("U{}", data.variants.len());
2112            let ident = Ident::new(&name, data.variants.span());
2113            quote! { ::object_rainbow::typenum::#ident }
2114        }
2115        Data::Union(data) => {
2116            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2117        }
2118    }
2119}
2120
2121fn gen_variants(data: &Data) -> proc_macro2::TokenStream {
2122    match data {
2123        Data::Struct(data) => {
2124            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2125        }
2126        Data::Enum(data) => {
2127            let variants = data.variants.iter().map(|v| &v.ident);
2128            quote! { #(#variants),* }
2129        }
2130        Data::Union(data) => {
2131            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2132        }
2133    }
2134}
2135
2136fn gen_variant_count(data: &Data) -> proc_macro2::TokenStream {
2137    match data {
2138        Data::Struct(data) => {
2139            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2140        }
2141        Data::Enum(data) => {
2142            let variant_count = data.variants.len();
2143            quote! { #variant_count }
2144        }
2145        Data::Union(data) => {
2146            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2147        }
2148    }
2149}
2150
2151fn gen_to_tag(data: &Data) -> proc_macro2::TokenStream {
2152    match data {
2153        Data::Struct(data) => {
2154            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2155        }
2156        Data::Enum(data) => {
2157            let to_tag = data.variants.iter().enumerate().map(|(i, v)| {
2158                let ident = &v.ident;
2159                quote_spanned! { ident.span() =>
2160                    Self::#ident => ::object_rainbow::enumkind::EnumTag::from_const::<#i>(),
2161                }
2162            });
2163            quote! {
2164                match self {
2165                    #(#to_tag)*
2166                }
2167            }
2168        }
2169        Data::Union(data) => {
2170            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2171        }
2172    }
2173}
2174
2175fn gen_from_tag(data: &Data) -> proc_macro2::TokenStream {
2176    match data {
2177        Data::Struct(data) => {
2178            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2179        }
2180        Data::Enum(data) => {
2181            let from_tag = data.variants.iter().enumerate().map(|(i, v)| {
2182                let ident = &v.ident;
2183                quote_spanned! { ident.span() =>
2184                    #i => Self::#ident,
2185                }
2186            });
2187            quote! {
2188                match tag.to_usize() {
2189                    #(#from_tag)*
2190                    _ => unreachable!(),
2191                }
2192            }
2193        }
2194        Data::Union(data) => {
2195            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2196        }
2197    }
2198}
2199
2200fn gen_kind(data: &Data) -> proc_macro2::TokenStream {
2201    match data {
2202        Data::Struct(data) => {
2203            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2204        }
2205        Data::Enum(data) => {
2206            let variants = data.variants.iter().map(|v| {
2207                let ident = &v.ident;
2208                quote_spanned! { ident.span() =>
2209                    Self::#ident {..} => __Kind::#ident,
2210                }
2211            });
2212            quote! {
2213                match self {
2214                    #(#variants)*
2215                }
2216            }
2217        }
2218        Data::Union(data) => {
2219            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2220        }
2221    }
2222}
2223
2224/// ```rust
2225/// use object_rainbow::{MaybeHasNiche, Size};
2226///
2227/// #[derive(Size, MaybeHasNiche)]
2228/// struct WithHole(bool, u8);
2229///
2230/// #[derive(Size, MaybeHasNiche)]
2231/// struct NoHole(u8, u8);
2232///
2233/// assert_eq!(Option::<WithHole>::SIZE, 2);
2234/// assert_eq!(Option::<NoHole>::SIZE, 3);
2235/// ```
2236#[proc_macro_derive(MaybeHasNiche)]
2237pub fn derive_maybe_has_niche(input: TokenStream) -> TokenStream {
2238    let input = parse_macro_input!(input as DeriveInput);
2239    let name = input.ident;
2240    let mn_array = gen_mn_array(&input.data);
2241    let (_, ty_generics, _) = input.generics.split_for_impl();
2242    let generics = match bounds_maybe_has_niche(input.generics.clone(), &input.data) {
2243        Ok(g) => g,
2244        Err(e) => return e.into_compile_error().into(),
2245    };
2246    let (impl_generics, _, where_clause) = generics.split_for_impl();
2247    let target = parse_for(&name, &input.attrs);
2248    let output = quote! {
2249        const _: () = {
2250            use ::object_rainbow::typenum::tarr;
2251
2252            #[automatically_derived]
2253            impl #impl_generics ::object_rainbow::MaybeHasNiche
2254            for #target #ty_generics #where_clause {
2255                type MnArray = #mn_array;
2256            }
2257        };
2258    };
2259    TokenStream::from(output)
2260}
2261
2262fn bounds_maybe_has_niche(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
2263    match data {
2264        Data::Struct(data) => {
2265            for f in data.fields.iter() {
2266                let ty = &f.ty;
2267                generics
2268                    .make_where_clause()
2269                    .predicates
2270                    .push(parse_quote_spanned! { ty.span() =>
2271                        #ty: ::object_rainbow::MaybeHasNiche<
2272                            MnArray: ::object_rainbow::MnArray<
2273                                MaybeNiche: ::object_rainbow::MaybeNiche
2274                            >
2275                        >
2276                    });
2277            }
2278        }
2279        Data::Enum(data) => {
2280            generics.params.push(parse_quote!(
2281                __N: ::object_rainbow::typenum::Unsigned
2282            ));
2283            for (i, v) in data.variants.iter().enumerate() {
2284                let mn_array = fields_mn_array(&v.fields, Some(i));
2285                generics
2286                    .make_where_clause()
2287                    .predicates
2288                    .push(parse_quote_spanned! { v.span() =>
2289                        #mn_array: ::object_rainbow::MnArray<
2290                            MaybeNiche: ::object_rainbow::NicheOr<N = __N>
2291                        >
2292                    });
2293                for f in v.fields.iter() {
2294                    let ty = &f.ty;
2295                    generics.make_where_clause().predicates.push(
2296                        parse_quote_spanned! { ty.span() =>
2297                            #ty: ::object_rainbow::MaybeHasNiche<
2298                                MnArray: ::object_rainbow::MnArray<
2299                                    MaybeNiche: ::object_rainbow::MaybeNiche
2300                                >
2301                            >
2302                        },
2303                    );
2304                }
2305            }
2306        }
2307        Data::Union(data) => {
2308            return Err(Error::new_spanned(
2309                data.union_token,
2310                "`union`s are not supported",
2311            ));
2312        }
2313    }
2314    Ok(generics)
2315}
2316
2317fn fields_mn_array(fields: &syn::Fields, variant: Option<usize>) -> proc_macro2::TokenStream {
2318    let mn_array = fields.iter().map(|f| {
2319        let ty = &f.ty;
2320        quote! {
2321            <
2322                <
2323                    #ty
2324                    as
2325                    ::object_rainbow::MaybeHasNiche
2326                >::MnArray
2327                as
2328                ::object_rainbow::MnArray
2329            >::MaybeNiche
2330        }
2331    });
2332    if let Some(variant) = variant {
2333        let kind_niche = quote! {
2334            ::object_rainbow::AutoEnumNiche<Self, #variant>
2335        };
2336        quote! {
2337            tarr![
2338                #kind_niche,
2339                ::object_rainbow::NoNiche<::object_rainbow::HackNiche<#variant>>, #(#mn_array),*
2340            ]
2341        }
2342    } else {
2343        quote! { tarr![#(#mn_array),*] }
2344    }
2345}
2346
2347fn gen_mn_array(data: &Data) -> proc_macro2::TokenStream {
2348    match data {
2349        Data::Struct(data) => fields_mn_array(&data.fields, None),
2350        Data::Enum(data) => {
2351            let mn_array = data.variants.iter().enumerate().map(|(i, v)| {
2352                let mn_array = fields_mn_array(&v.fields, Some(i));
2353                quote! { <#mn_array as ::object_rainbow::MnArray>::MaybeNiche }
2354            });
2355            quote! {
2356                ::object_rainbow::NicheFoldOrArray<tarr![#(#mn_array),*]>
2357            }
2358        }
2359        Data::Union(data) => {
2360            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
2361        }
2362    }
2363}
2364
2365#[proc_macro_attribute]
2366pub fn derive_for_wrapped(args: TokenStream, input: TokenStream) -> TokenStream {
2367    let input = parse_macro_input!(input as ItemTrait);
2368    let sup = if args.is_empty() {
2369        let sup = input.supertraits.clone();
2370        quote!(#sup)
2371    } else {
2372        args.into()
2373    };
2374    let name = input.ident.clone();
2375    let generics = input.generics.clone();
2376    let (_, ty_generics, _) = generics.split_for_impl();
2377    let mut derived = Vec::new();
2378    for (path, extra) in [
2379        (
2380            quote!(map_extra::MappedExtra),
2381            vec![(quote!(__M), quote!(#sup))],
2382        ),
2383        (quote!(length_prefixed::Lp), vec![]),
2384    ] {
2385        let mut generics = input.generics.clone();
2386        generics.params.push(parse_quote! {
2387            __T: #name #ty_generics
2388        });
2389        for (i, ty) in &extra {
2390            generics.params.push(parse_quote! {
2391                #i: #ty
2392            });
2393        }
2394        let (impl_generics, _, where_clause) = generics.split_for_impl();
2395        let i = input
2396            .items
2397            .clone()
2398            .into_iter()
2399            .map(|i| match i {
2400                TraitItem::Const(i) => ImplItem::Const({
2401                    let const_token = i.const_token;
2402                    let ident = i.ident;
2403                    let colon_token = i.colon_token;
2404                    let ty = i.ty;
2405                    let semi_token = i.semi_token;
2406                    parse_quote! {
2407                        #const_token
2408                        #ident
2409                        #colon_token
2410                        #ty
2411                        =
2412                        <__T as #name #ty_generics>::#ident
2413                        #semi_token
2414                    }
2415                }),
2416                TraitItem::Fn(i) => ImplItem::Fn({
2417                    let mut sig = i.sig;
2418                    let ident = sig.ident.clone();
2419                    let args = sig
2420                        .inputs
2421                        .iter_mut()
2422                        .enumerate()
2423                        .map(|(n, i)| match i {
2424                            FnArg::Receiver(receiver) => {
2425                                let reference = receiver.reference.as_ref().map(|(and, _)| and);
2426                                let mutability = receiver.mutability.as_ref();
2427                                let ident = &receiver.self_token;
2428                                quote!(#reference #mutability *#ident)
2429                            }
2430                            FnArg::Typed(pat_type) => {
2431                                let ident = Ident::new(&format!("arg{n}"), pat_type.span());
2432                                *pat_type.pat = parse_quote!(#ident);
2433                                quote!(#ident)
2434                            }
2435                        })
2436                        .collect::<Vec<_>>();
2437                    parse_quote! {
2438                        #sig
2439                        {
2440                            <__T as #name #ty_generics>::#ident(
2441                                #(#args),*
2442                            )
2443                        }
2444                    }
2445                }),
2446                TraitItem::Type(i) => ImplItem::Type({
2447                    let type_token = i.type_token;
2448                    let ident = i.ident;
2449                    let semi_token = i.semi_token;
2450                    parse_quote! {
2451                        #type_token
2452                        #ident
2453                        =
2454                        <__T as #name #ty_generics>::#ident
2455                        #semi_token
2456                    }
2457                }),
2458                _ => unimplemented!("unknown/unsupported item"),
2459            })
2460            .collect::<Vec<_>>();
2461        let extra = extra.into_iter().map(|(k, _)| k);
2462        derived.push(quote! {
2463            impl #impl_generics #name #ty_generics for ::object_rainbow::#path<
2464                __T,
2465                #(#extra),*
2466            >
2467            #where_clause
2468            {
2469                #(#i)*
2470            }
2471        });
2472    }
2473    let output = quote! {
2474        #input
2475
2476        #(#derived)*
2477    };
2478    output.into()
2479}