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    recursive: bool,
416}
417
418fn parse_recursive(attrs: &[Attribute]) -> syn::Result<bool> {
419    let mut r = false;
420    for attr in attrs {
421        if attr_str(attr).as_deref() == Some("topology") {
422            let ContainerTopologyArgs { recursive } = attr.parse_args()?;
423            if recursive {
424                r = true;
425            }
426        }
427    }
428    Ok(r)
429}
430
431#[derive(Debug, FromMeta)]
432#[darling(derive_syn_parse)]
433struct FieldTopologyArgs {
434    bound: Option<Path>,
435    #[darling(default)]
436    unchecked: bool,
437    with: Option<Expr>,
438    #[darling(default, rename = "unstable_mutual")]
439    mutual: bool,
440}
441
442fn bounds_topological(
443    mut generics: Generics,
444    data: &Data,
445    attrs: &[Attribute],
446    name: &Ident,
447    defs: &mut Vec<proc_macro2::TokenStream>,
448) -> syn::Result<Generics> {
449    let recursive = parse_recursive(attrs)?;
450    let g = &bounds_g(&generics);
451    let g_clone = generics.clone();
452    let (impl_generics, ty_generics, where_clause) = g_clone.split_for_impl();
453    let this = quote_spanned! { name.span() =>
454        #name #ty_generics
455    };
456    let bound = if recursive {
457        quote! { ::object_rainbow::Traversible }
458    } else {
459        quote! { ::object_rainbow::Topological }
460    };
461    match data {
462        Data::Struct(data) => {
463            'field: for f in data.fields.iter() {
464                let ty = &f.ty;
465                let mut b = None;
466                for attr in &f.attrs {
467                    if attr_str(attr).as_deref() == Some("topology") {
468                        let FieldTopologyArgs {
469                            bound,
470                            unchecked,
471                            mutual,
472                            ..
473                        } = attr.parse_args()?;
474                        if mutual {
475                            let conditional =
476                                format!("__ConditionalTopology_{}", f.ident.as_ref().unwrap());
477                            let conditional = Ident::new(&conditional, f.span());
478                            defs.push(quote! {
479                                #[allow(non_camel_case_types)]
480                                trait #conditional #impl_generics #where_clause {
481                                    fn traverse(
482                                        &self, visitor: &mut impl ::object_rainbow::PointVisitor,
483                                    ) where #this: ::object_rainbow::Traversible;
484                                }
485
486                                impl #impl_generics #conditional #ty_generics for #ty #where_clause {
487                                    fn traverse(
488                                        &self, visitor: &mut impl ::object_rainbow::PointVisitor,
489                                    ) where #this: ::object_rainbow::Traversible {
490                                        ::object_rainbow::Topological::traverse(self, visitor)
491                                    }
492                                }
493                            });
494                            b = Some(parse_quote!(#conditional #ty_generics));
495                        }
496                        if unchecked {
497                            continue 'field;
498                        }
499                        if let Some(bound) = bound {
500                            b = Some(bound);
501                        }
502                    }
503                }
504                let bound = if let Some(bound) = b {
505                    quote! { #bound }
506                } else {
507                    bound.clone()
508                };
509                if type_contains_generics(GContext { g, always: false }, ty) {
510                    generics.make_where_clause().predicates.push(
511                        parse_quote_spanned! { ty.span() =>
512                            #ty: #bound
513                        },
514                    );
515                }
516            }
517        }
518        Data::Enum(data) => {
519            for v in data.variants.iter() {
520                'field: for (i, f) in v.fields.iter().enumerate() {
521                    let ty = &f.ty;
522                    let mut b = None;
523                    for attr in &f.attrs {
524                        if attr_str(attr).as_deref() == Some("topology") {
525                            let FieldTopologyArgs {
526                                bound,
527                                unchecked,
528                                mutual,
529                                ..
530                            } = attr.parse_args()?;
531                            if mutual {
532                                let conditional = format!("__ConditionalTopology_{i}");
533                                let conditional = Ident::new(&conditional, f.span());
534                                defs.push(quote! {
535                                #[allow(non_camel_case_types)]
536                                trait #conditional #impl_generics #where_clause {
537                                    fn traverse(
538                                        &self, visitor: &mut impl ::object_rainbow::PointVisitor,
539                                    ) where #this: ::object_rainbow::Traversible;
540                                }
541
542                                impl #impl_generics #conditional #ty_generics for #ty #where_clause {
543                                    fn traverse(
544                                        &self, visitor: &mut impl ::object_rainbow::PointVisitor,
545                                    ) where #this: ::object_rainbow::Traversible {
546                                        ::object_rainbow::Topological::traverse(self, visitor)
547                                    }
548                                }
549                            });
550                            }
551                            if unchecked {
552                                continue 'field;
553                            }
554                            if let Some(bound) = bound {
555                                b = Some(bound);
556                            }
557                        }
558                    }
559                    let bound = if let Some(bound) = b {
560                        quote! { #bound }
561                    } else {
562                        bound.clone()
563                    };
564                    if type_contains_generics(GContext { g, always: false }, ty) {
565                        generics.make_where_clause().predicates.push(
566                            parse_quote_spanned! { ty.span() =>
567                                #ty: #bound
568                            },
569                        );
570                    }
571                }
572            }
573        }
574        Data::Union(data) => {
575            return Err(Error::new_spanned(
576                data.union_token,
577                "`union`s are not supported",
578            ));
579        }
580    }
581    if recursive {
582        generics
583            .make_where_clause()
584            .predicates
585            .push(parse_quote_spanned! { name.span() =>
586                Self: ::object_rainbow::ToOutput + ::object_rainbow::Tagged
587            });
588    }
589    Ok(generics)
590}
591
592fn fields_traverse(
593    fields: &syn::Fields,
594    ty_generics: &TypeGenerics<'_>,
595) -> proc_macro2::TokenStream {
596    match fields {
597        syn::Fields::Named(fields) => {
598            let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
599            let traverse = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
600                let ty = &f.ty;
601                let mut w = None;
602                let mut b = None;
603                for attr in &f.attrs {
604                    if attr_str(attr).as_deref() == Some("topology") {
605                        let FieldTopologyArgs {
606                            with,
607                            bound,
608                            mutual,
609                            ..
610                        } = match attr.parse_args() {
611                            Ok(args) => args,
612                            Err(e) => return e.into_compile_error(),
613                        };
614                        if mutual {
615                            let conditional = format!("__ConditionalTopology_{i}");
616                            let conditional = Ident::new(&conditional, f.span());
617                            w = Some(parse_quote!(traverse));
618                            b = Some(parse_quote!(#conditional #ty_generics));
619                        }
620                        if let Some(with) = with {
621                            w = Some(with);
622                        }
623                        if let Some(bound) = bound {
624                            b = Some(bound);
625                        }
626                    }
627                }
628                if let Some(with) = w {
629                    if let Some(bound) = b {
630                        quote_spanned! { f.ty.span() =>
631                            <#ty as #bound>::#with(#i, visitor)
632                        }
633                    } else {
634                        quote_spanned! { f.ty.span() =>
635                            #with(#i, visitor)
636                        }
637                    }
638                } else {
639                    quote_spanned! { f.ty.span() =>
640                        #i.traverse(visitor)
641                    }
642                }
643            });
644            quote! {
645                { #(#let_self),* } => {
646                    #(#traverse);*
647                }
648            }
649        }
650        syn::Fields::Unnamed(fields) => {
651            let let_self = fields
652                .unnamed
653                .iter()
654                .enumerate()
655                .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
656            let traverse = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
657                let ty = &f.ty;
658                let mut w = None;
659                let mut b = None;
660                for attr in &f.attrs {
661                    if attr_str(attr).as_deref() == Some("topology") {
662                        let FieldTopologyArgs {
663                            with,
664                            bound,
665                            mutual,
666                            ..
667                        } = match attr.parse_args() {
668                            Ok(args) => args,
669                            Err(e) => return e.into_compile_error(),
670                        };
671                        if mutual {
672                            let conditional = format!("__ConditionalTopology_{i}");
673                            let conditional = Ident::new(&conditional, f.span());
674                            w = Some(parse_quote!(traverse));
675                            b = Some(parse_quote!(#conditional #ty_generics));
676                        }
677                        if let Some(with) = with {
678                            w = Some(with);
679                        }
680                        if let Some(bound) = bound {
681                            b = Some(bound);
682                        }
683                    }
684                }
685                if let Some(with) = w {
686                    if let Some(bound) = b {
687                        quote_spanned! { f.ty.span() =>
688                            <#ty as #bound>::#with(#i, visitor)
689                        }
690                    } else {
691                        quote_spanned! { f.ty.span() =>
692                            #with(#i, visitor)
693                        }
694                    }
695                } else {
696                    quote_spanned! { f.ty.span() =>
697                        #i.traverse(visitor)
698                    }
699                }
700            });
701            quote! {
702                (#(#let_self),*) => {
703                    #(#traverse);*
704                }
705            }
706        }
707        syn::Fields::Unit => quote! {
708            => {}
709        },
710    }
711}
712
713fn gen_traverse(data: &Data, ty_generics: &TypeGenerics<'_>) -> proc_macro2::TokenStream {
714    match data {
715        Data::Struct(data) => {
716            let arm = fields_traverse(&data.fields, ty_generics);
717            quote! {
718                match self {
719                    Self #arm
720                }
721            }
722        }
723        Data::Enum(data) => {
724            let to_output = data.variants.iter().map(|v| {
725                let ident = &v.ident;
726                let arm = fields_traverse(&v.fields, ty_generics);
727                quote! { Self::#ident #arm }
728            });
729            quote! {
730                let kind = ::object_rainbow::Enum::kind(self);
731                let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
732                tag.traverse(visitor);
733                match self {
734                    #(#to_output)*
735                }
736            }
737        }
738        Data::Union(data) => {
739            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
740        }
741    }
742}
743
744#[proc_macro_derive(Tagged, attributes(tags))]
745pub fn derive_tagged(input: TokenStream) -> TokenStream {
746    let input = parse_macro_input!(input as DeriveInput);
747    let name = input.ident;
748    let mut errors = Vec::new();
749    let generics = match bounds_tagged(input.generics, &input.data, &mut errors) {
750        Ok(g) => g,
751        Err(e) => return e.into_compile_error().into(),
752    };
753    let tags = gen_tags(&input.data, &input.attrs, &mut errors);
754    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
755    let errors = errors.into_iter().map(|e| e.into_compile_error());
756    let target = parse_for(&name, &input.attrs);
757    let output = quote! {
758        #(#errors)*
759
760        #[automatically_derived]
761        impl #impl_generics ::object_rainbow::Tagged for #target #ty_generics #where_clause {
762            const TAGS: ::object_rainbow::Tags = #tags;
763        }
764    };
765    TokenStream::from(output)
766}
767
768struct FieldTagArgs {
769    skip: bool,
770}
771
772impl Parse for FieldTagArgs {
773    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
774        let mut skip = false;
775        while !input.is_empty() {
776            let ident = input.parse::<Ident>()?;
777            if ident.to_string().as_str() != "skip" {
778                return Err(Error::new(ident.span(), "expected: skip"));
779            }
780            skip = true;
781            if !input.is_empty() {
782                input.parse::<Comma>()?;
783            }
784        }
785        Ok(Self { skip })
786    }
787}
788
789fn bounds_tagged(
790    mut generics: Generics,
791    data: &Data,
792    errors: &mut Vec<Error>,
793) -> syn::Result<Generics> {
794    let g = &bounds_g(&generics);
795    match data {
796        Data::Struct(data) => {
797            for f in data.fields.iter() {
798                let mut skip = false;
799                for attr in &f.attrs {
800                    if attr_str(attr).as_deref() == Some("tags") {
801                        match attr.parse_args::<FieldTagArgs>() {
802                            Ok(args) => skip |= args.skip,
803                            Err(e) => errors.push(e),
804                        }
805                    }
806                }
807                if !skip {
808                    let ty = &f.ty;
809                    if type_contains_generics(GContext { g, always: false }, ty) {
810                        generics.make_where_clause().predicates.push(
811                            parse_quote_spanned! { ty.span() =>
812                                #ty: ::object_rainbow::Tagged
813                            },
814                        );
815                    }
816                }
817            }
818        }
819        Data::Enum(data) => {
820            for v in data.variants.iter() {
821                for f in v.fields.iter() {
822                    let mut skip = false;
823                    for attr in &f.attrs {
824                        if attr_str(attr).as_deref() == Some("tags") {
825                            match attr.parse_args::<FieldTagArgs>() {
826                                Ok(args) => skip |= args.skip,
827                                Err(e) => errors.push(e),
828                            }
829                        }
830                    }
831                    if !skip {
832                        let ty = &f.ty;
833                        if type_contains_generics(GContext { g, always: false }, ty) {
834                            generics.make_where_clause().predicates.push(
835                                parse_quote_spanned! { ty.span() =>
836                                    #ty: ::object_rainbow::Tagged
837                                },
838                            );
839                        }
840                    }
841                }
842            }
843        }
844        Data::Union(data) => {
845            return Err(Error::new_spanned(
846                data.union_token,
847                "`union`s are not supported",
848            ));
849        }
850    }
851    Ok(generics)
852}
853
854struct StructTagArgs {
855    tags: Vec<LitStr>,
856}
857
858impl Parse for StructTagArgs {
859    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
860        let mut tags = Vec::new();
861        while !input.is_empty() {
862            let tag = input.parse::<LitStr>()?;
863            tags.push(tag);
864            if !input.is_empty() {
865                input.parse::<Comma>()?;
866            }
867        }
868        Ok(Self { tags })
869    }
870}
871
872fn fields_tags(fields: &syn::Fields) -> Vec<proc_macro2::TokenStream> {
873    fields
874        .iter()
875        .filter_map(|f| {
876            let mut skip = false;
877            for attr in &f.attrs {
878                if attr_str(attr).as_deref() == Some("tags") {
879                    skip |= attr.parse_args::<FieldTagArgs>().ok()?.skip;
880                }
881            }
882            let ty = &f.ty;
883            (!skip).then_some(quote! { <#ty as ::object_rainbow::Tagged>::TAGS })
884        })
885        .collect()
886}
887
888fn gen_tags(data: &Data, attrs: &[Attribute], errors: &mut Vec<Error>) -> proc_macro2::TokenStream {
889    match data {
890        Data::Struct(data) => {
891            let mut tags = Vec::new();
892            for attr in attrs {
893                if attr_str(attr).as_deref() == Some("tags") {
894                    match attr.parse_args::<StructTagArgs>() {
895                        Ok(mut args) => tags.append(&mut args.tags),
896                        Err(e) => errors.push(e),
897                    }
898                }
899            }
900            let nested = fields_tags(&data.fields);
901            if nested.len() == 1 && tags.is_empty() {
902                let nested = nested.into_iter().next().unwrap();
903                quote! {
904                    #nested
905                }
906            } else {
907                quote! {
908                    ::object_rainbow::Tags(&[#(#tags),*], &[#(&#nested),*])
909                }
910            }
911        }
912        Data::Enum(data) => {
913            let mut tags = Vec::new();
914            for attr in attrs {
915                if attr_str(attr).as_deref() == Some("tags") {
916                    match attr.parse_args::<StructTagArgs>() {
917                        Ok(mut args) => tags.append(&mut args.tags),
918                        Err(e) => errors.push(e),
919                    }
920                }
921            }
922            let mut nested: Vec<_> = data
923                .variants
924                .iter()
925                .flat_map(|v| fields_tags(&v.fields))
926                .collect();
927            let kind_tags = quote! {
928                <
929                    <
930                        <
931                            Self
932                            as
933                            ::object_rainbow::Enum
934                        >::Kind
935                        as
936                        ::object_rainbow::enumkind::EnumKind
937                    >::Tag
938                    as  ::object_rainbow::Tagged
939                >::TAGS
940            };
941            nested.insert(0, kind_tags);
942            if nested.len() == 1 && tags.is_empty() {
943                let nested = nested.into_iter().next().unwrap();
944                quote! {
945                    #nested
946                }
947            } else {
948                quote! {
949                    ::object_rainbow::Tags(&[#(#tags),*], &[#(&#nested),*])
950                }
951            }
952        }
953        Data::Union(data) => {
954            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
955        }
956    }
957}
958
959#[proc_macro_derive(Size)]
960pub fn derive_size(input: TokenStream) -> TokenStream {
961    let input = parse_macro_input!(input as DeriveInput);
962    let name = input.ident;
963    let size_arr = gen_size_arr(&input.data);
964    let size = gen_size(&input.data);
965    let generics = match bounds_size(input.generics.clone(), &input.data, &size_arr) {
966        Ok(g) => g,
967        Err(e) => return e.into_compile_error().into(),
968    };
969    let (_, ty_generics, where_clause) = generics.split_for_impl();
970    let mut generics = input.generics;
971    generics.params.push(parse_quote!(
972        __Output: ::object_rainbow::typenum::Unsigned
973    ));
974    let (impl_generics, _, _) = generics.split_for_impl();
975    let target = parse_for(&name, &input.attrs);
976    let output = quote! {
977        const _: () = {
978            use ::object_rainbow::typenum::tarr;
979
980            #[automatically_derived]
981            impl #impl_generics ::object_rainbow::Size for #target #ty_generics #where_clause {
982                const SIZE: usize = #size;
983
984                type Size = <#size_arr as ::object_rainbow::typenum::FoldAdd>::Output;
985            }
986        };
987    };
988    TokenStream::from(output)
989}
990
991fn bounds_size(
992    mut generics: Generics,
993    data: &Data,
994    size_arr: &proc_macro2::TokenStream,
995) -> syn::Result<Generics> {
996    let g = &bounds_g(&generics);
997    match data {
998        Data::Struct(data) => {
999            for f in data.fields.iter() {
1000                let ty = &f.ty;
1001                if type_contains_generics(GContext { g, always: false }, ty) {
1002                    generics.make_where_clause().predicates.push(
1003                        parse_quote_spanned! { ty.span() =>
1004                            #ty: ::object_rainbow::Size
1005                        },
1006                    );
1007                }
1008            }
1009        }
1010        Data::Enum(data) => {
1011            for v in data.variants.iter() {
1012                for f in v.fields.iter() {
1013                    let ty = &f.ty;
1014                    if type_contains_generics(GContext { g, always: false }, ty) {
1015                        generics.make_where_clause().predicates.push(
1016                            parse_quote_spanned! { ty.span() =>
1017                                #ty: ::object_rainbow::Size
1018                            },
1019                        );
1020                    }
1021                }
1022            }
1023            for v in data.variants.iter().skip(1) {
1024                let arr = fields_size_arr(&v.fields, true);
1025                generics.make_where_clause().predicates.push(parse_quote!(
1026                    #arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
1027                ));
1028            }
1029        }
1030        Data::Union(data) => {
1031            return Err(Error::new_spanned(
1032                data.union_token,
1033                "`union`s are not supported",
1034            ));
1035        }
1036    }
1037    generics.make_where_clause().predicates.push(parse_quote!(
1038        #size_arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
1039    ));
1040    Ok(generics)
1041}
1042
1043fn fields_size_arr(fields: &syn::Fields, as_enum: bool) -> proc_macro2::TokenStream {
1044    let kind_size = 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::Size
1056        >::Size
1057    };
1058    if fields.is_empty() {
1059        return if as_enum {
1060            quote! { tarr![#kind_size, ::object_rainbow::typenum::consts::U0] }
1061        } else {
1062            quote! { tarr![::object_rainbow::typenum::consts::U0] }
1063        };
1064    }
1065    let size_arr = fields.iter().map(|f| {
1066        let ty = &f.ty;
1067        quote! { <#ty as ::object_rainbow::Size>::Size }
1068    });
1069    if as_enum {
1070        quote! { tarr![#kind_size, #(#size_arr),*] }
1071    } else {
1072        quote! { tarr![#(#size_arr),*] }
1073    }
1074}
1075
1076fn gen_size_arr(data: &Data) -> proc_macro2::TokenStream {
1077    match data {
1078        Data::Struct(data) => fields_size_arr(&data.fields, false),
1079        Data::Enum(data) => {
1080            if let Some(v) = data.variants.first() {
1081                fields_size_arr(&v.fields, true)
1082            } else {
1083                Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
1084                    .into_compile_error()
1085            }
1086        }
1087        Data::Union(data) => {
1088            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1089        }
1090    }
1091}
1092
1093fn fields_size(fields: &syn::Fields) -> proc_macro2::TokenStream {
1094    if fields.is_empty() {
1095        return quote! {0};
1096    }
1097    let size = fields.iter().map(|f| {
1098        let ty = &f.ty;
1099        quote! { <#ty as ::object_rainbow::Size>::SIZE }
1100    });
1101    quote! {
1102        #(#size)+*
1103    }
1104}
1105
1106fn gen_size(data: &Data) -> proc_macro2::TokenStream {
1107    match data {
1108        Data::Struct(data) => fields_size(&data.fields),
1109        Data::Enum(data) => {
1110            if let Some(v) = data.variants.first() {
1111                let size = fields_size(&v.fields);
1112                let kind_size = quote! {
1113                    <
1114                        <
1115                            <
1116                                Self
1117                                as
1118                                ::object_rainbow::Enum
1119                            >::Kind
1120                            as
1121                            ::object_rainbow::enumkind::EnumKind
1122                        >::Tag
1123                        as  ::object_rainbow::Size
1124                    >::SIZE
1125                };
1126                quote! { #kind_size + #size }
1127            } else {
1128                Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
1129                    .into_compile_error()
1130            }
1131        }
1132        Data::Union(data) => {
1133            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1134        }
1135    }
1136}
1137
1138#[proc_macro_derive(Parse, attributes(parse))]
1139pub fn derive_parse(input: TokenStream) -> TokenStream {
1140    let input = parse_macro_input!(input as DeriveInput);
1141    let name = input.ident;
1142    let generics = input.generics.clone();
1143    let (_, ty_generics, _) = generics.split_for_impl();
1144    let mut defs = Vec::new();
1145    let generics = match bounds_parse(input.generics, &input.data, &input.attrs, &name, &mut defs) {
1146        Ok(g) => g,
1147        Err(e) => return e.into_compile_error().into(),
1148    };
1149    let parse = gen_parse(&input.data, &ty_generics);
1150    let (impl_generics, _, where_clause) = generics.split_for_impl();
1151    let target = parse_for(&name, &input.attrs);
1152    let output = quote! {
1153        const _: () = {
1154            #(#defs)*
1155
1156            #[automatically_derived]
1157            impl #impl_generics ::object_rainbow::Parse<__I> for #target #ty_generics
1158            #where_clause
1159            {
1160                fn parse(mut input: __I) -> ::object_rainbow::Result<Self> {
1161                    #parse
1162                }
1163            }
1164        };
1165    };
1166    TokenStream::from(output)
1167}
1168
1169#[derive(Debug, FromMeta)]
1170#[darling(derive_syn_parse)]
1171struct ParseArgs {
1172    bound: Option<Type>,
1173    #[darling(default)]
1174    unchecked: bool,
1175    with: Option<Expr>,
1176    #[darling(default, rename = "unstable_mutual")]
1177    mutual: bool,
1178}
1179
1180fn conditional_parse_name(f: &Field, inline: bool) -> Ident {
1181    let infix = if inline { "ParseInline" } else { "Parse" };
1182    let conditional = format!("__Conditional{infix}_{}", f.ident.as_ref().unwrap());
1183    Ident::new(&conditional, f.span())
1184}
1185
1186fn conditional_parse_input(inline: bool) -> proc_macro2::TokenStream {
1187    if inline {
1188        quote!(&mut impl ::object_rainbow::PointInput<Extra = Self::E>)
1189    } else {
1190        quote!(impl ::object_rainbow::PointInput<Extra = Self::E>)
1191    }
1192}
1193
1194fn conditional_parse_method(inline: bool) -> proc_macro2::TokenStream {
1195    if inline {
1196        quote!(parse_inline)
1197    } else {
1198        quote!(parse)
1199    }
1200}
1201
1202fn bounds_parse(
1203    mut generics: Generics,
1204    data: &Data,
1205    attrs: &[Attribute],
1206    name: &Ident,
1207    defs: &mut Vec<proc_macro2::TokenStream>,
1208) -> syn::Result<Generics> {
1209    let g_clone = generics.clone();
1210    let (impl_generics, ty_generics, where_clause) = g_clone.split_for_impl();
1211    let this = quote_spanned! { name.span() =>
1212        #name #ty_generics
1213    };
1214    let recursive = parse_recursive(attrs)?;
1215    let tr = |last| match (last, recursive) {
1216        (true, true) => {
1217            quote!(::object_rainbow::Parse<__I> + ::object_rainbow::Object<__I::Extra>)
1218        }
1219        (true, false) => quote!(::object_rainbow::Parse<__I>),
1220        (false, true) => {
1221            quote!(::object_rainbow::ParseInline<__I> + ::object_rainbow::Inline<__I::Extra>)
1222        }
1223        (false, false) => quote!(::object_rainbow::ParseInline<__I>),
1224    };
1225    match data {
1226        Data::Struct(data) => {
1227            let last_at = data.fields.len().checked_sub(1).unwrap_or_default();
1228            'field: for (i, f) in data.fields.iter().enumerate() {
1229                let last = i == last_at;
1230                let ty = &f.ty;
1231                let mut b = None;
1232                for attr in &f.attrs {
1233                    if attr_str(attr).as_deref() == Some("parse") {
1234                        let ParseArgs {
1235                            bound,
1236                            unchecked,
1237                            mutual,
1238                            ..
1239                        } = attr.parse_args::<ParseArgs>()?;
1240                        if mutual {
1241                            let conditional = conditional_parse_name(f, !last);
1242                            let mut g_clone = g_clone.clone();
1243                            g_clone.params.push(parse_quote!(
1244                                __E: ::core::marker::Send + ::core::marker::Sync
1245                            ));
1246                            let (impl_generics_extra, _, _) = g_clone.split_for_impl();
1247                            let input_type = conditional_parse_input(!last);
1248                            let parse_method = conditional_parse_method(!last);
1249                            defs.push(quote! {
1250                                #[allow(non_camel_case_types)]
1251                                trait #conditional #impl_generics: ::object_rainbow::BoundPair
1252                                #where_clause
1253                                {
1254                                    fn parse(
1255                                        input: #input_type,
1256                                    ) -> ::object_rainbow::Result<Self::T>
1257                                    where #this: ::object_rainbow::Object<Self::E>;
1258                                }
1259
1260                                impl #impl_generics_extra #conditional #ty_generics
1261                                    for (#ty, __E)
1262                                #where_clause
1263                                {
1264                                    fn parse(
1265                                        input: #input_type,
1266                                    ) -> ::object_rainbow::Result<Self::T>
1267                                    where #this: ::object_rainbow::Object<Self::E> {
1268                                        input.#parse_method::<Self::T>()
1269                                    }
1270                                }
1271                            });
1272                            b = Some(parse_quote!(#conditional #ty_generics));
1273                        }
1274                        if unchecked {
1275                            continue 'field;
1276                        }
1277                        if let Some(bound) = bound {
1278                            b = Some(bound);
1279                        }
1280                    }
1281                }
1282                if let Some(bound) = b {
1283                    generics.make_where_clause().predicates.push(
1284                        parse_quote_spanned! { ty.span() =>
1285                            (#ty, __I::Extra): ::object_rainbow::BoundPair<
1286                                T = #ty, E = __I::Extra
1287                            > + #bound
1288                        },
1289                    );
1290                } else {
1291                    let tr = tr(last);
1292                    generics.make_where_clause().predicates.push(
1293                        parse_quote_spanned! { ty.span() =>
1294                            #ty: #tr
1295                        },
1296                    );
1297                }
1298            }
1299        }
1300        Data::Enum(data) => {
1301            for v in data.variants.iter() {
1302                let last_at = v.fields.len().checked_sub(1).unwrap_or_default();
1303                'field: for (i, f) in v.fields.iter().enumerate() {
1304                    let ty = &f.ty;
1305                    let mut b = None;
1306                    for attr in &f.attrs {
1307                        if attr_str(attr).as_deref() == Some("parse") {
1308                            let ParseArgs {
1309                                bound, unchecked, ..
1310                            } = attr.parse_args::<ParseArgs>()?;
1311                            if unchecked {
1312                                continue 'field;
1313                            }
1314                            if let Some(bound) = bound {
1315                                b = Some(bound);
1316                            }
1317                        }
1318                    }
1319                    if let Some(bound) = b {
1320                        generics.make_where_clause().predicates.push(
1321                            parse_quote_spanned! { ty.span() =>
1322                                (#ty, __I::Extra): ::object_rainbow::BoundPair<
1323                                    T = #ty, E = __I::Extra
1324                                > + #bound
1325                            },
1326                        );
1327                    } else {
1328                        let last = i == last_at;
1329                        let tr = tr(last);
1330                        generics.make_where_clause().predicates.push(
1331                            parse_quote_spanned! { ty.span() =>
1332                                #ty: #tr
1333                            },
1334                        );
1335                    }
1336                }
1337            }
1338        }
1339        Data::Union(data) => {
1340            return Err(Error::new_spanned(
1341                data.union_token,
1342                "`union`s are not supported",
1343            ));
1344        }
1345    }
1346    generics.params.push(if recursive {
1347        parse_quote!(__I: ::object_rainbow::PointInput<
1348            Extra: ::core::marker::Send + ::core::marker::Sync + ::core::clone::Clone
1349        >)
1350    } else {
1351        parse_quote!(__I: ::object_rainbow::ParseInput)
1352    });
1353    Ok(generics)
1354}
1355
1356fn gen_parse(data: &Data, ty_generics: &TypeGenerics<'_>) -> proc_macro2::TokenStream {
1357    match data {
1358        Data::Struct(data) => {
1359            let arm = fields_parse(&data.fields, ty_generics);
1360            quote! { Ok(Self #arm)}
1361        }
1362        Data::Enum(data) => {
1363            let parse = data.variants.iter().map(|v| {
1364                let ident = &v.ident;
1365                let arm = fields_parse(&v.fields, ty_generics);
1366                quote! {
1367                    <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
1368                }
1369            });
1370            quote! {
1371                Ok(match input.parse_inline()? {
1372                    #(#parse)*
1373                })
1374            }
1375        }
1376        Data::Union(data) => {
1377            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1378        }
1379    }
1380}
1381
1382fn fields_parse(fields: &syn::Fields, ty_generics: &TypeGenerics<'_>) -> proc_macro2::TokenStream {
1383    let last_at = fields.len().checked_sub(1).unwrap_or_default();
1384    match fields {
1385        syn::Fields::Named(fields) => {
1386            let parse = fields.named.iter().enumerate().map(|(i, f)| {
1387                let last = i == last_at;
1388                let ty = &f.ty;
1389                let mut w = None;
1390                let mut b = None;
1391                for attr in &f.attrs {
1392                    if attr_str(attr).as_deref() == Some("parse") {
1393                        let ParseArgs {
1394                            with,
1395                            bound,
1396                            mutual,
1397                            ..
1398                        } = match attr.parse_args::<ParseArgs>() {
1399                            Ok(args) => args,
1400                            Err(e) => return e.into_compile_error(),
1401                        };
1402                        if mutual {
1403                            let conditional = format!(
1404                                "__Conditional{}_{}",
1405                                if last { "Parse" } else { "ParseInline" },
1406                                f.ident.as_ref().unwrap(),
1407                            );
1408                            let conditional = Ident::new(&conditional, f.span());
1409                            w = Some(parse_quote!(parse));
1410                            b = Some(parse_quote!(#conditional #ty_generics));
1411                        }
1412                        if let Some(with) = with {
1413                            w = Some(with);
1414                        }
1415                        if let Some(bound) = bound {
1416                            b = Some(bound);
1417                        }
1418                    }
1419                }
1420                let i = f.ident.as_ref().unwrap();
1421                if let Some(with) = w {
1422                    let arg = if last {
1423                        quote!(input)
1424                    } else {
1425                        quote!(&mut input)
1426                    };
1427                    if let Some(bound) = b {
1428                        quote_spanned! { f.ty.span() =>
1429                            #i: <(#ty, __I::Extra) as #bound>::#with(#arg)?
1430                        }
1431                    } else {
1432                        quote_spanned! { f.ty.span() =>
1433                            #i: #with(#arg)?
1434                        }
1435                    }
1436                } else {
1437                    let method = if last {
1438                        quote!(parse)
1439                    } else {
1440                        quote!(parse_inline)
1441                    };
1442                    quote_spanned! { f.ty.span() =>
1443                        #i: input.#method()?
1444                    }
1445                }
1446            });
1447            quote! { { #(#parse),* } }
1448        }
1449        syn::Fields::Unnamed(fields) => {
1450            let parse = fields.unnamed.iter().enumerate().map(|(i, f)| {
1451                let ty = &f.ty;
1452                let mut w = None;
1453                let mut b = None;
1454                for attr in &f.attrs {
1455                    if attr_str(attr).as_deref() == Some("parse") {
1456                        let ParseArgs { with, bound, .. } = match attr.parse_args::<ParseArgs>() {
1457                            Ok(args) => args,
1458                            Err(e) => return e.into_compile_error(),
1459                        };
1460                        if let Some(with) = with {
1461                            w = Some(with);
1462                        }
1463                        if let Some(bound) = bound {
1464                            b = Some(bound);
1465                        }
1466                    }
1467                }
1468                let last = i == last_at;
1469                if let Some(with) = w {
1470                    let arg = if last {
1471                        quote!(input)
1472                    } else {
1473                        quote!(&mut input)
1474                    };
1475                    if let Some(bound) = b {
1476                        quote_spanned! { f.ty.span() =>
1477                            <(#ty, __I::Extra) as #bound>::#with(#arg)?
1478                        }
1479                    } else {
1480                        quote_spanned! { f.ty.span() =>
1481                            #with(#arg)?
1482                        }
1483                    }
1484                } else {
1485                    let method = if last {
1486                        quote!(parse)
1487                    } else {
1488                        quote!(parse_inline)
1489                    };
1490                    quote_spanned! { f.ty.span() =>
1491                        input.#method()?
1492                    }
1493                }
1494            });
1495            quote! { (#(#parse),*) }
1496        }
1497        syn::Fields::Unit => quote! {},
1498    }
1499}
1500
1501#[proc_macro_derive(ParseInline, attributes(parse))]
1502pub fn derive_parse_inline(input: TokenStream) -> TokenStream {
1503    let input = parse_macro_input!(input as DeriveInput);
1504    let name = input.ident;
1505    let generics = input.generics.clone();
1506    let (_, ty_generics, _) = generics.split_for_impl();
1507    let generics = match bounds_parse_inline(input.generics, &input.data, &input.attrs) {
1508        Ok(g) => g,
1509        Err(e) => return e.into_compile_error().into(),
1510    };
1511    let parse_inline = gen_parse_inline(&input.data);
1512    let (impl_generics, _, where_clause) = generics.split_for_impl();
1513    let target = parse_for(&name, &input.attrs);
1514    let output = quote! {
1515        #[automatically_derived]
1516        impl #impl_generics ::object_rainbow::ParseInline<__I> for #target #ty_generics #where_clause {
1517            fn parse_inline(input: &mut __I) -> ::object_rainbow::Result<Self> {
1518                #parse_inline
1519            }
1520        }
1521    };
1522    TokenStream::from(output)
1523}
1524
1525fn bounds_parse_inline(
1526    mut generics: Generics,
1527    data: &Data,
1528    attrs: &[Attribute],
1529) -> syn::Result<Generics> {
1530    let recursive = parse_recursive(attrs)?;
1531    let tr = if recursive {
1532        quote!(::object_rainbow::ParseInline<__I> + ::object_rainbow::Inline<__I::Extra>)
1533    } else {
1534        quote!(::object_rainbow::ParseInline<__I>)
1535    };
1536    match data {
1537        Data::Struct(data) => {
1538            'field: for f in data.fields.iter() {
1539                let ty = &f.ty;
1540                let mut b = None;
1541                for attr in &f.attrs {
1542                    if attr_str(attr).as_deref() == Some("parse") {
1543                        let ParseArgs {
1544                            bound, unchecked, ..
1545                        } = attr.parse_args::<ParseArgs>()?;
1546                        if unchecked {
1547                            continue 'field;
1548                        }
1549                        if let Some(bound) = bound {
1550                            b = Some(bound);
1551                        }
1552                    }
1553                }
1554                if let Some(bound) = b {
1555                    generics.make_where_clause().predicates.push(
1556                        parse_quote_spanned! { ty.span() =>
1557                            (#ty, __I::Extra): #bound
1558                        },
1559                    );
1560                } else {
1561                    generics.make_where_clause().predicates.push(
1562                        parse_quote_spanned! { ty.span() =>
1563                            #ty: #tr
1564                        },
1565                    );
1566                }
1567            }
1568        }
1569        Data::Enum(data) => {
1570            for v in data.variants.iter() {
1571                'field: for f in v.fields.iter() {
1572                    let ty = &f.ty;
1573                    let mut b = None;
1574                    for attr in &f.attrs {
1575                        if attr_str(attr).as_deref() == Some("parse") {
1576                            let ParseArgs {
1577                                bound, unchecked, ..
1578                            } = attr.parse_args::<ParseArgs>()?;
1579                            if unchecked {
1580                                continue 'field;
1581                            }
1582                            if let Some(bound) = bound {
1583                                b = Some(bound);
1584                            }
1585                        }
1586                    }
1587                    if let Some(bound) = b {
1588                        generics.make_where_clause().predicates.push(
1589                            parse_quote_spanned! { ty.span() =>
1590                                (#ty, __I::Extra): #bound
1591                            },
1592                        );
1593                    } else {
1594                        generics.make_where_clause().predicates.push(
1595                            parse_quote_spanned! { ty.span() =>
1596                                #ty: #tr
1597                            },
1598                        );
1599                    }
1600                }
1601            }
1602        }
1603        Data::Union(data) => {
1604            return Err(Error::new_spanned(
1605                data.union_token,
1606                "`union`s are not supported",
1607            ));
1608        }
1609    }
1610    generics.params.push(if recursive {
1611        parse_quote!(__I: ::object_rainbow::PointInput<
1612            Extra: ::core::marker::Send + ::core::marker::Sync
1613        >)
1614    } else {
1615        parse_quote!(__I: ::object_rainbow::ParseInput)
1616    });
1617    Ok(generics)
1618}
1619
1620fn fields_parse_inline(fields: &syn::Fields) -> proc_macro2::TokenStream {
1621    match fields {
1622        syn::Fields::Named(fields) => {
1623            let parse = fields.named.iter().map(|f| {
1624                let i = f.ident.as_ref().unwrap();
1625                quote_spanned! { f.ty.span() =>
1626                    #i: input.parse_inline()?
1627                }
1628            });
1629            quote! { { #(#parse),* } }
1630        }
1631        syn::Fields::Unnamed(fields) => {
1632            let parse = fields.unnamed.iter().map(|f| {
1633                quote_spanned! { f.ty.span() =>
1634                    input.parse_inline()?
1635                }
1636            });
1637            quote! { (#(#parse),*) }
1638        }
1639        syn::Fields::Unit => quote! {},
1640    }
1641}
1642
1643fn gen_parse_inline(data: &Data) -> proc_macro2::TokenStream {
1644    match data {
1645        Data::Struct(data) => {
1646            let arm = fields_parse_inline(&data.fields);
1647            quote! { Ok(Self #arm) }
1648        }
1649        Data::Enum(data) => {
1650            let parse_inline = data.variants.iter().map(|v| {
1651                let ident = &v.ident;
1652                let arm = fields_parse_inline(&v.fields);
1653                quote! {
1654                    <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
1655                }
1656            });
1657            quote! {
1658                Ok(match input.parse_inline()? {
1659                    #(#parse_inline)*
1660                })
1661            }
1662        }
1663        Data::Union(data) => {
1664            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1665        }
1666    }
1667}
1668
1669#[proc_macro_derive(ParseAsInline)]
1670pub fn derive_parse_as_inline(input: TokenStream) -> TokenStream {
1671    let input = parse_macro_input!(input as DeriveInput);
1672    let name = input.ident;
1673    let generics = input.generics.clone();
1674    let (_, ty_generics, _) = generics.split_for_impl();
1675    let generics = match bounds_parse_as_inline(input.generics, &name) {
1676        Ok(g) => g,
1677        Err(e) => return e.into_compile_error().into(),
1678    };
1679    let (impl_generics, _, where_clause) = generics.split_for_impl();
1680    let target = parse_for(&name, &input.attrs);
1681    let output = quote! {
1682        #[automatically_derived]
1683        impl #impl_generics ::object_rainbow::Parse<__I> for #target #ty_generics #where_clause {
1684            fn parse(input: __I) -> ::object_rainbow::Result<Self> {
1685                ::object_rainbow::ParseInline::<__I>::parse_as_inline(input)
1686            }
1687        }
1688    };
1689    TokenStream::from(output)
1690}
1691
1692fn bounds_parse_as_inline(mut generics: Generics, name: &Ident) -> syn::Result<Generics> {
1693    generics
1694        .make_where_clause()
1695        .predicates
1696        .push(parse_quote_spanned! { name.span() =>
1697            Self: ::object_rainbow::ParseInline::<__I>
1698        });
1699    generics
1700        .params
1701        .push(parse_quote!(__I: ::object_rainbow::ParseInput));
1702    Ok(generics)
1703}
1704
1705fn parse_path(attr: &Attribute) -> syn::Result<Type> {
1706    attr.parse_args::<LitStr>()?.parse()
1707}
1708
1709fn attr_str(attr: &Attribute) -> Option<String> {
1710    Some(attr.path().get_ident()?.to_string())
1711}
1712
1713#[proc_macro_derive(Enum, attributes(enumtag))]
1714pub fn derive_enum(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 = input.generics;
1720    let variants = gen_variants(&input.data);
1721    let variant_count = gen_variant_count(&input.data);
1722    let to_tag = gen_to_tag(&input.data);
1723    let from_tag = gen_from_tag(&input.data);
1724    let kind = gen_kind(&input.data);
1725    let (impl_generics, _, where_clause) = generics.split_for_impl();
1726    let mut errors = Vec::new();
1727    let mut enumtag = None;
1728    for attr in &input.attrs {
1729        if attr_str(attr).as_deref() == Some("enumtag") {
1730            match parse_path(attr) {
1731                Ok(path) => {
1732                    if enumtag.is_some() {
1733                        errors.push(Error::new_spanned(path, "duplicate tag"));
1734                    } else {
1735                        enumtag = Some(path);
1736                    }
1737                }
1738                Err(e) => errors.push(e),
1739            }
1740        }
1741    }
1742    let enumtag = enumtag
1743        .unwrap_or_else(|| parse_quote!(::object_rainbow::numeric::Le<::core::num::NonZero<u8>>));
1744    let errors = errors.into_iter().map(|e| e.into_compile_error());
1745    let target = parse_for(&name, &input.attrs);
1746    let output = quote! {
1747        const _: () = {
1748            #(#errors)*
1749
1750            use ::object_rainbow::enumkind::EnumKind;
1751
1752            #[derive(Clone, Copy, ::object_rainbow::ParseAsInline)]
1753            pub enum __Kind {
1754                #variants
1755            }
1756
1757            #[automatically_derived]
1758            impl ::object_rainbow::enumkind::EnumKind for __Kind {
1759                type Tag = ::object_rainbow::enumkind::EnumTag<
1760                    #enumtag,
1761                    #variant_count,
1762                >;
1763
1764                fn to_tag(self) -> Self::Tag {
1765                    #to_tag
1766                }
1767
1768                fn from_tag(tag: Self::Tag) -> Self {
1769                    #from_tag
1770                }
1771            }
1772
1773            impl<I: ::object_rainbow::ParseInput> ::object_rainbow::ParseInline<I> for __Kind {
1774                fn parse_inline(input: &mut I) -> ::object_rainbow::Result<Self> {
1775                    Ok(::object_rainbow::enumkind::EnumKind::from_tag(input.parse_inline()?))
1776                }
1777            }
1778
1779            #[automatically_derived]
1780            impl #impl_generics ::object_rainbow::Enum for #target #ty_generics #where_clause {
1781                type Kind = __Kind;
1782
1783                fn kind(&self) -> Self::Kind {
1784                    #kind
1785                }
1786            }
1787        };
1788    };
1789    TokenStream::from(output)
1790}
1791
1792fn gen_variants(data: &Data) -> proc_macro2::TokenStream {
1793    match data {
1794        Data::Struct(data) => {
1795            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1796        }
1797        Data::Enum(data) => {
1798            let variants = data.variants.iter().map(|v| &v.ident);
1799            quote! { #(#variants),* }
1800        }
1801        Data::Union(data) => {
1802            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1803        }
1804    }
1805}
1806
1807fn gen_variant_count(data: &Data) -> proc_macro2::TokenStream {
1808    match data {
1809        Data::Struct(data) => {
1810            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1811        }
1812        Data::Enum(data) => {
1813            let variant_count = data.variants.len();
1814            quote! { #variant_count }
1815        }
1816        Data::Union(data) => {
1817            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1818        }
1819    }
1820}
1821
1822fn gen_to_tag(data: &Data) -> proc_macro2::TokenStream {
1823    match data {
1824        Data::Struct(data) => {
1825            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1826        }
1827        Data::Enum(data) => {
1828            let to_tag = data.variants.iter().enumerate().map(|(i, v)| {
1829                let ident = &v.ident;
1830                quote_spanned! { ident.span() =>
1831                    Self::#ident => ::object_rainbow::enumkind::EnumTag::from_const::<#i>(),
1832                }
1833            });
1834            quote! {
1835                match self {
1836                    #(#to_tag)*
1837                }
1838            }
1839        }
1840        Data::Union(data) => {
1841            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1842        }
1843    }
1844}
1845
1846fn gen_from_tag(data: &Data) -> proc_macro2::TokenStream {
1847    match data {
1848        Data::Struct(data) => {
1849            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1850        }
1851        Data::Enum(data) => {
1852            let from_tag = data.variants.iter().enumerate().map(|(i, v)| {
1853                let ident = &v.ident;
1854                quote_spanned! { ident.span() =>
1855                    #i => Self::#ident,
1856                }
1857            });
1858            quote! {
1859                match tag.to_usize() {
1860                    #(#from_tag)*
1861                    _ => unreachable!(),
1862                }
1863            }
1864        }
1865        Data::Union(data) => {
1866            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1867        }
1868    }
1869}
1870
1871fn gen_kind(data: &Data) -> proc_macro2::TokenStream {
1872    match data {
1873        Data::Struct(data) => {
1874            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1875        }
1876        Data::Enum(data) => {
1877            let variants = data.variants.iter().map(|v| {
1878                let ident = &v.ident;
1879                quote_spanned! { ident.span() =>
1880                    Self::#ident {..} => __Kind::#ident,
1881                }
1882            });
1883            quote! {
1884                match self {
1885                    #(#variants)*
1886                }
1887            }
1888        }
1889        Data::Union(data) => {
1890            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1891        }
1892    }
1893}
1894
1895#[proc_macro_derive(MaybeHasNiche)]
1896pub fn derive_maybe_has_niche(input: TokenStream) -> TokenStream {
1897    let input = parse_macro_input!(input as DeriveInput);
1898    let name = input.ident;
1899    let mn_array = gen_mn_array(&input.data);
1900    let (_, ty_generics, _) = input.generics.split_for_impl();
1901    let generics = match bounds_maybe_has_niche(input.generics.clone(), &input.data) {
1902        Ok(g) => g,
1903        Err(e) => return e.into_compile_error().into(),
1904    };
1905    let (impl_generics, _, where_clause) = generics.split_for_impl();
1906    let target = parse_for(&name, &input.attrs);
1907    let output = quote! {
1908        const _: () = {
1909            use ::object_rainbow::typenum::tarr;
1910
1911            #[automatically_derived]
1912            impl #impl_generics ::object_rainbow::MaybeHasNiche for #target #ty_generics #where_clause {
1913                type MnArray = #mn_array;
1914            }
1915        };
1916    };
1917    TokenStream::from(output)
1918}
1919
1920fn bounds_maybe_has_niche(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
1921    match data {
1922        Data::Struct(data) => {
1923            for f in data.fields.iter() {
1924                let ty = &f.ty;
1925                generics
1926                    .make_where_clause()
1927                    .predicates
1928                    .push(parse_quote_spanned! { ty.span() =>
1929                        #ty: ::object_rainbow::MaybeHasNiche<
1930                            MnArray: ::object_rainbow::MnArray<
1931                                MaybeNiche: ::object_rainbow::MaybeNiche
1932                            >
1933                        >
1934                    });
1935            }
1936        }
1937        Data::Enum(data) => {
1938            generics.params.push(parse_quote!(
1939                __N: ::object_rainbow::typenum::Unsigned
1940            ));
1941            for (i, v) in data.variants.iter().enumerate() {
1942                let mn_array = fields_mn_array(&v.fields, Some(i));
1943                generics
1944                    .make_where_clause()
1945                    .predicates
1946                    .push(parse_quote_spanned! { v.span() =>
1947                        #mn_array: ::object_rainbow::MnArray<
1948                            MaybeNiche: ::object_rainbow::NicheOr<N = __N>
1949                        >
1950                    });
1951                for f in v.fields.iter() {
1952                    let ty = &f.ty;
1953                    generics.make_where_clause().predicates.push(
1954                        parse_quote_spanned! { ty.span() =>
1955                            #ty: ::object_rainbow::MaybeHasNiche<
1956                                MnArray: ::object_rainbow::MnArray<
1957                                    MaybeNiche: ::object_rainbow::MaybeNiche
1958                                >
1959                            >
1960                        },
1961                    );
1962                }
1963            }
1964        }
1965        Data::Union(data) => {
1966            return Err(Error::new_spanned(
1967                data.union_token,
1968                "`union`s are not supported",
1969            ));
1970        }
1971    }
1972    Ok(generics)
1973}
1974
1975fn fields_mn_array(fields: &syn::Fields, variant: Option<usize>) -> proc_macro2::TokenStream {
1976    let mn_array = fields.iter().map(|f| {
1977        let ty = &f.ty;
1978        quote! {
1979            <
1980                <
1981                    #ty
1982                    as
1983                    ::object_rainbow::MaybeHasNiche
1984                >::MnArray
1985                as
1986                ::object_rainbow::MnArray
1987            >::MaybeNiche
1988        }
1989    });
1990    if let Some(variant) = variant {
1991        let kind_niche = quote! {
1992            ::object_rainbow::AutoEnumNiche<Self, #variant>
1993        };
1994        quote! { tarr![#kind_niche, ::object_rainbow::NoNiche<::object_rainbow::HackNiche<#variant>>, #(#mn_array),*] }
1995    } else {
1996        quote! { tarr![#(#mn_array),*] }
1997    }
1998}
1999
2000fn gen_mn_array(data: &Data) -> proc_macro2::TokenStream {
2001    match data {
2002        Data::Struct(data) => fields_mn_array(&data.fields, None),
2003        Data::Enum(data) => {
2004            let mn_array = data.variants.iter().enumerate().map(|(i, v)| {
2005                let mn_array = fields_mn_array(&v.fields, Some(i));
2006                quote! { <#mn_array as ::object_rainbow::MnArray>::MaybeNiche }
2007            });
2008            quote! {
2009                ::object_rainbow::NicheFoldOrArray<tarr![#(#mn_array),*]>
2010            }
2011        }
2012        Data::Union(data) => {
2013            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
2014        }
2015    }
2016}