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