Skip to main content

object_rainbow_derive/
lib.rs

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