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 = 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    generics.params.push(parse_quote!(
988        __Output: ::object_rainbow::typenum::Unsigned
989    ));
990    let (impl_generics, _, _) = generics.split_for_impl();
991    let target = parse_for(&name, &input.attrs);
992    let output = quote! {
993        const _: () = {
994            use ::object_rainbow::typenum::tarr;
995
996            #[automatically_derived]
997            impl #impl_generics ::object_rainbow::Size for #target #ty_generics #where_clause {
998                const SIZE: usize = #size;
999
1000                type Size = <#size_arr as ::object_rainbow::typenum::FoldAdd>::Output;
1001            }
1002        };
1003    };
1004    TokenStream::from(output)
1005}
1006
1007fn bounds_size(
1008    mut generics: Generics,
1009    data: &Data,
1010    size_arr: &proc_macro2::TokenStream,
1011) -> syn::Result<Generics> {
1012    let g = &bounds_g(&generics);
1013    match data {
1014        Data::Struct(data) => {
1015            for f in data.fields.iter() {
1016                let ty = &f.ty;
1017                if type_contains_generics(GContext { g, always: false }, ty) {
1018                    generics.make_where_clause().predicates.push(
1019                        parse_quote_spanned! { ty.span() =>
1020                            #ty: ::object_rainbow::Size
1021                        },
1022                    );
1023                }
1024            }
1025        }
1026        Data::Enum(data) => {
1027            for v in data.variants.iter() {
1028                for f in v.fields.iter() {
1029                    let ty = &f.ty;
1030                    if type_contains_generics(GContext { g, always: false }, ty) {
1031                        generics.make_where_clause().predicates.push(
1032                            parse_quote_spanned! { ty.span() =>
1033                                #ty: ::object_rainbow::Size
1034                            },
1035                        );
1036                    }
1037                }
1038            }
1039            for v in data.variants.iter().skip(1) {
1040                let arr = fields_size_arr(&v.fields, true);
1041                generics.make_where_clause().predicates.push(parse_quote!(
1042                    #arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
1043                ));
1044            }
1045        }
1046        Data::Union(data) => {
1047            return Err(Error::new_spanned(
1048                data.union_token,
1049                "`union`s are not supported",
1050            ));
1051        }
1052    }
1053    generics.make_where_clause().predicates.push(parse_quote!(
1054        #size_arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
1055    ));
1056    Ok(generics)
1057}
1058
1059fn fields_size_arr(fields: &syn::Fields, as_enum: bool) -> proc_macro2::TokenStream {
1060    let kind_size = quote! {
1061        <
1062            <
1063                <
1064                    Self
1065                    as
1066                    ::object_rainbow::Enum
1067                >::Kind
1068                as
1069                ::object_rainbow::enumkind::EnumKind
1070            >::Tag
1071            as  ::object_rainbow::Size
1072        >::Size
1073    };
1074    if fields.is_empty() {
1075        return if as_enum {
1076            quote! { tarr![#kind_size, ::object_rainbow::typenum::consts::U0] }
1077        } else {
1078            quote! { tarr![::object_rainbow::typenum::consts::U0] }
1079        };
1080    }
1081    let size_arr = fields.iter().map(|f| {
1082        let ty = &f.ty;
1083        quote! { <#ty as ::object_rainbow::Size>::Size }
1084    });
1085    if as_enum {
1086        quote! { tarr![#kind_size, #(#size_arr),*] }
1087    } else {
1088        quote! { tarr![#(#size_arr),*] }
1089    }
1090}
1091
1092fn gen_size_arr(data: &Data) -> proc_macro2::TokenStream {
1093    match data {
1094        Data::Struct(data) => fields_size_arr(&data.fields, false),
1095        Data::Enum(data) => {
1096            if let Some(v) = data.variants.first() {
1097                fields_size_arr(&v.fields, true)
1098            } else {
1099                Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
1100                    .into_compile_error()
1101            }
1102        }
1103        Data::Union(data) => {
1104            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1105        }
1106    }
1107}
1108
1109fn fields_size(fields: &syn::Fields) -> proc_macro2::TokenStream {
1110    if fields.is_empty() {
1111        return quote! {0};
1112    }
1113    let size = fields.iter().map(|f| {
1114        let ty = &f.ty;
1115        quote! { <#ty as ::object_rainbow::Size>::SIZE }
1116    });
1117    quote! {
1118        #(#size)+*
1119    }
1120}
1121
1122fn gen_size(data: &Data) -> proc_macro2::TokenStream {
1123    match data {
1124        Data::Struct(data) => fields_size(&data.fields),
1125        Data::Enum(data) => {
1126            if let Some(v) = data.variants.first() {
1127                let size = fields_size(&v.fields);
1128                let kind_size = quote! {
1129                    <
1130                        <
1131                            <
1132                                Self
1133                                as
1134                                ::object_rainbow::Enum
1135                            >::Kind
1136                            as
1137                            ::object_rainbow::enumkind::EnumKind
1138                        >::Tag
1139                        as  ::object_rainbow::Size
1140                    >::SIZE
1141                };
1142                quote! { #kind_size + #size }
1143            } else {
1144                Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
1145                    .into_compile_error()
1146            }
1147        }
1148        Data::Union(data) => {
1149            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1150        }
1151    }
1152}
1153
1154#[proc_macro_derive(Parse, attributes(parse))]
1155pub fn derive_parse(input: TokenStream) -> TokenStream {
1156    let input = parse_macro_input!(input as DeriveInput);
1157    let name = input.ident;
1158    let generics = input.generics.clone();
1159    let (_, ty_generics, _) = generics.split_for_impl();
1160    let mut defs = Vec::new();
1161    let generics = match bounds_parse(input.generics, &input.data, &input.attrs, &name, &mut defs) {
1162        Ok(g) => g,
1163        Err(e) => return e.into_compile_error().into(),
1164    };
1165    let parse = gen_parse(&input.data, &ty_generics);
1166    let (impl_generics, _, where_clause) = generics.split_for_impl();
1167    let target = parse_for(&name, &input.attrs);
1168    let output = quote! {
1169        const _: () = {
1170            #(#defs)*
1171
1172            #[automatically_derived]
1173            impl #impl_generics ::object_rainbow::Parse<__I> for #target #ty_generics
1174            #where_clause
1175            {
1176                fn parse(mut input: __I) -> ::object_rainbow::Result<Self> {
1177                    #parse
1178                }
1179            }
1180        };
1181    };
1182    TokenStream::from(output)
1183}
1184
1185#[derive(Debug, FromMeta)]
1186#[darling(derive_syn_parse)]
1187struct ParseArgs {
1188    bound: Option<Type>,
1189    #[darling(default)]
1190    unchecked: bool,
1191    with: Option<Expr>,
1192    #[darling(default, rename = "unstable_mutual")]
1193    mutual: bool,
1194}
1195
1196fn conditional_parse_name(f: &Field, inline: bool) -> Ident {
1197    let infix = if inline { "ParseInline" } else { "Parse" };
1198    let conditional = format!("__Conditional{infix}_{}", f.ident.as_ref().unwrap());
1199    Ident::new(&conditional, f.span())
1200}
1201
1202fn conditional_parse_input(inline: bool) -> proc_macro2::TokenStream {
1203    if inline {
1204        quote!(&mut impl ::object_rainbow::PointInput<Extra = Self::E>)
1205    } else {
1206        quote!(impl ::object_rainbow::PointInput<Extra = Self::E>)
1207    }
1208}
1209
1210fn conditional_parse_method(inline: bool) -> proc_macro2::TokenStream {
1211    if inline {
1212        quote!(parse_inline)
1213    } else {
1214        quote!(parse)
1215    }
1216}
1217
1218fn bounds_parse(
1219    mut generics: Generics,
1220    data: &Data,
1221    attrs: &[Attribute],
1222    name: &Ident,
1223    defs: &mut Vec<proc_macro2::TokenStream>,
1224) -> syn::Result<Generics> {
1225    let g_clone = generics.clone();
1226    let (impl_generics, ty_generics, where_clause) = g_clone.split_for_impl();
1227    let this = quote_spanned! { name.span() =>
1228        #name #ty_generics
1229    };
1230    let (recursive, _) = parse_recursive_inline(attrs)?;
1231    let tr = |last| match (last, recursive) {
1232        (true, true) => {
1233            quote!(::object_rainbow::Parse<__I> + ::object_rainbow::Object<__I::Extra>)
1234        }
1235        (true, false) => quote!(::object_rainbow::Parse<__I>),
1236        (false, true) => {
1237            quote!(::object_rainbow::ParseInline<__I> + ::object_rainbow::Inline<__I::Extra>)
1238        }
1239        (false, false) => quote!(::object_rainbow::ParseInline<__I>),
1240    };
1241    match data {
1242        Data::Struct(data) => {
1243            let last_at = data.fields.len().checked_sub(1).unwrap_or_default();
1244            'field: for (i, f) in data.fields.iter().enumerate() {
1245                let last = i == last_at;
1246                let ty = &f.ty;
1247                let mut b = None;
1248                for attr in &f.attrs {
1249                    if attr_str(attr).as_deref() == Some("parse") {
1250                        let ParseArgs {
1251                            bound,
1252                            unchecked,
1253                            mutual,
1254                            ..
1255                        } = attr.parse_args::<ParseArgs>()?;
1256                        if mutual {
1257                            let conditional = conditional_parse_name(f, !last);
1258                            let mut g_clone = g_clone.clone();
1259                            g_clone.params.push(parse_quote!(
1260                                __E: ::core::marker::Send + ::core::marker::Sync
1261                            ));
1262                            let (impl_generics_extra, _, _) = g_clone.split_for_impl();
1263                            let input_type = conditional_parse_input(!last);
1264                            let parse_method = conditional_parse_method(!last);
1265                            defs.push(quote! {
1266                                #[allow(non_camel_case_types)]
1267                                trait #conditional #impl_generics: ::object_rainbow::BoundPair
1268                                #where_clause
1269                                {
1270                                    fn parse(
1271                                        input: #input_type,
1272                                    ) -> ::object_rainbow::Result<Self::T>
1273                                    where #this: ::object_rainbow::Object<Self::E>;
1274                                }
1275
1276                                impl #impl_generics_extra #conditional #ty_generics
1277                                    for (#ty, __E)
1278                                #where_clause
1279                                {
1280                                    fn parse(
1281                                        input: #input_type,
1282                                    ) -> ::object_rainbow::Result<Self::T>
1283                                    where #this: ::object_rainbow::Object<Self::E> {
1284                                        input.#parse_method::<Self::T>()
1285                                    }
1286                                }
1287                            });
1288                            b = Some(parse_quote!(#conditional #ty_generics));
1289                        }
1290                        if unchecked {
1291                            continue 'field;
1292                        }
1293                        if let Some(bound) = bound {
1294                            b = Some(bound);
1295                        }
1296                    }
1297                }
1298                if let Some(bound) = b {
1299                    generics.make_where_clause().predicates.push(
1300                        parse_quote_spanned! { ty.span() =>
1301                            (#ty, __I::Extra): ::object_rainbow::BoundPair<
1302                                T = #ty, E = __I::Extra
1303                            > + #bound
1304                        },
1305                    );
1306                } else {
1307                    let tr = tr(last);
1308                    generics.make_where_clause().predicates.push(
1309                        parse_quote_spanned! { ty.span() =>
1310                            #ty: #tr
1311                        },
1312                    );
1313                }
1314            }
1315        }
1316        Data::Enum(data) => {
1317            for v in data.variants.iter() {
1318                let last_at = v.fields.len().checked_sub(1).unwrap_or_default();
1319                'field: for (i, f) in v.fields.iter().enumerate() {
1320                    let ty = &f.ty;
1321                    let mut b = None;
1322                    for attr in &f.attrs {
1323                        if attr_str(attr).as_deref() == Some("parse") {
1324                            let ParseArgs {
1325                                bound, unchecked, ..
1326                            } = attr.parse_args::<ParseArgs>()?;
1327                            if unchecked {
1328                                continue 'field;
1329                            }
1330                            if let Some(bound) = bound {
1331                                b = Some(bound);
1332                            }
1333                        }
1334                    }
1335                    if let Some(bound) = b {
1336                        generics.make_where_clause().predicates.push(
1337                            parse_quote_spanned! { ty.span() =>
1338                                (#ty, __I::Extra): ::object_rainbow::BoundPair<
1339                                    T = #ty, E = __I::Extra
1340                                > + #bound
1341                            },
1342                        );
1343                    } else {
1344                        let last = i == last_at;
1345                        let tr = tr(last);
1346                        generics.make_where_clause().predicates.push(
1347                            parse_quote_spanned! { ty.span() =>
1348                                #ty: #tr
1349                            },
1350                        );
1351                    }
1352                }
1353            }
1354        }
1355        Data::Union(data) => {
1356            return Err(Error::new_spanned(
1357                data.union_token,
1358                "`union`s are not supported",
1359            ));
1360        }
1361    }
1362    generics.params.push(if recursive {
1363        parse_quote!(__I: ::object_rainbow::PointInput<
1364            Extra: ::core::marker::Send + ::core::marker::Sync + ::core::clone::Clone
1365        >)
1366    } else {
1367        parse_quote!(__I: ::object_rainbow::ParseInput)
1368    });
1369    Ok(generics)
1370}
1371
1372fn gen_parse(data: &Data, ty_generics: &TypeGenerics<'_>) -> proc_macro2::TokenStream {
1373    match data {
1374        Data::Struct(data) => {
1375            let arm = fields_parse(&data.fields, ty_generics);
1376            quote! { Ok(Self #arm)}
1377        }
1378        Data::Enum(data) => {
1379            let parse = data.variants.iter().map(|v| {
1380                let ident = &v.ident;
1381                let arm = fields_parse(&v.fields, ty_generics);
1382                quote! {
1383                    <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
1384                }
1385            });
1386            quote! {
1387                Ok(match input.parse_inline()? {
1388                    #(#parse)*
1389                })
1390            }
1391        }
1392        Data::Union(data) => {
1393            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1394        }
1395    }
1396}
1397
1398fn fields_parse(fields: &syn::Fields, ty_generics: &TypeGenerics<'_>) -> proc_macro2::TokenStream {
1399    let last_at = fields.len().checked_sub(1).unwrap_or_default();
1400    match fields {
1401        syn::Fields::Named(fields) => {
1402            let parse = fields.named.iter().enumerate().map(|(i, f)| {
1403                let last = i == last_at;
1404                let ty = &f.ty;
1405                let mut w = None;
1406                let mut b = None;
1407                for attr in &f.attrs {
1408                    if attr_str(attr).as_deref() == Some("parse") {
1409                        let ParseArgs {
1410                            with,
1411                            bound,
1412                            mutual,
1413                            ..
1414                        } = match attr.parse_args::<ParseArgs>() {
1415                            Ok(args) => args,
1416                            Err(e) => return e.into_compile_error(),
1417                        };
1418                        if mutual {
1419                            let conditional = format!(
1420                                "__Conditional{}_{}",
1421                                if last { "Parse" } else { "ParseInline" },
1422                                f.ident.as_ref().unwrap(),
1423                            );
1424                            let conditional = Ident::new(&conditional, f.span());
1425                            w = Some(parse_quote!(parse));
1426                            b = Some(parse_quote!(#conditional #ty_generics));
1427                        }
1428                        if let Some(with) = with {
1429                            w = Some(with);
1430                        }
1431                        if let Some(bound) = bound {
1432                            b = Some(bound);
1433                        }
1434                    }
1435                }
1436                let i = f.ident.as_ref().unwrap();
1437                if let Some(with) = w {
1438                    let arg = if last {
1439                        quote!(input)
1440                    } else {
1441                        quote!(&mut input)
1442                    };
1443                    if let Some(bound) = b {
1444                        quote_spanned! { f.ty.span() =>
1445                            #i: <(#ty, __I::Extra) as #bound>::#with(#arg)?
1446                        }
1447                    } else {
1448                        quote_spanned! { f.ty.span() =>
1449                            #i: #with(#arg)?
1450                        }
1451                    }
1452                } else {
1453                    let method = if last {
1454                        quote!(parse)
1455                    } else {
1456                        quote!(parse_inline)
1457                    };
1458                    quote_spanned! { f.ty.span() =>
1459                        #i: input.#method()?
1460                    }
1461                }
1462            });
1463            quote! { { #(#parse),* } }
1464        }
1465        syn::Fields::Unnamed(fields) => {
1466            let parse = fields.unnamed.iter().enumerate().map(|(i, f)| {
1467                let ty = &f.ty;
1468                let mut w = None;
1469                let mut b = None;
1470                for attr in &f.attrs {
1471                    if attr_str(attr).as_deref() == Some("parse") {
1472                        let ParseArgs { with, bound, .. } = match attr.parse_args::<ParseArgs>() {
1473                            Ok(args) => args,
1474                            Err(e) => return e.into_compile_error(),
1475                        };
1476                        if let Some(with) = with {
1477                            w = Some(with);
1478                        }
1479                        if let Some(bound) = bound {
1480                            b = Some(bound);
1481                        }
1482                    }
1483                }
1484                let last = i == last_at;
1485                if let Some(with) = w {
1486                    let arg = if last {
1487                        quote!(input)
1488                    } else {
1489                        quote!(&mut input)
1490                    };
1491                    if let Some(bound) = b {
1492                        quote_spanned! { f.ty.span() =>
1493                            <(#ty, __I::Extra) as #bound>::#with(#arg)?
1494                        }
1495                    } else {
1496                        quote_spanned! { f.ty.span() =>
1497                            #with(#arg)?
1498                        }
1499                    }
1500                } else {
1501                    let method = if last {
1502                        quote!(parse)
1503                    } else {
1504                        quote!(parse_inline)
1505                    };
1506                    quote_spanned! { f.ty.span() =>
1507                        input.#method()?
1508                    }
1509                }
1510            });
1511            quote! { (#(#parse),*) }
1512        }
1513        syn::Fields::Unit => quote! {},
1514    }
1515}
1516
1517#[proc_macro_derive(ParseInline, attributes(parse))]
1518pub fn derive_parse_inline(input: TokenStream) -> TokenStream {
1519    let input = parse_macro_input!(input as DeriveInput);
1520    let name = input.ident;
1521    let generics = input.generics.clone();
1522    let (_, ty_generics, _) = generics.split_for_impl();
1523    let generics = match bounds_parse_inline(input.generics, &input.data, &input.attrs) {
1524        Ok(g) => g,
1525        Err(e) => return e.into_compile_error().into(),
1526    };
1527    let parse_inline = gen_parse_inline(&input.data);
1528    let (impl_generics, _, where_clause) = generics.split_for_impl();
1529    let target = parse_for(&name, &input.attrs);
1530    let output = quote! {
1531        #[automatically_derived]
1532        impl #impl_generics ::object_rainbow::ParseInline<__I> for #target #ty_generics #where_clause {
1533            fn parse_inline(input: &mut __I) -> ::object_rainbow::Result<Self> {
1534                #parse_inline
1535            }
1536        }
1537    };
1538    TokenStream::from(output)
1539}
1540
1541fn bounds_parse_inline(
1542    mut generics: Generics,
1543    data: &Data,
1544    attrs: &[Attribute],
1545) -> syn::Result<Generics> {
1546    let (recursive, _) = parse_recursive_inline(attrs)?;
1547    let tr = if recursive {
1548        quote!(::object_rainbow::ParseInline<__I> + ::object_rainbow::Inline<__I::Extra>)
1549    } else {
1550        quote!(::object_rainbow::ParseInline<__I>)
1551    };
1552    match data {
1553        Data::Struct(data) => {
1554            'field: for f in data.fields.iter() {
1555                let ty = &f.ty;
1556                let mut b = None;
1557                for attr in &f.attrs {
1558                    if attr_str(attr).as_deref() == Some("parse") {
1559                        let ParseArgs {
1560                            bound, unchecked, ..
1561                        } = attr.parse_args::<ParseArgs>()?;
1562                        if unchecked {
1563                            continue 'field;
1564                        }
1565                        if let Some(bound) = bound {
1566                            b = Some(bound);
1567                        }
1568                    }
1569                }
1570                if let Some(bound) = b {
1571                    generics.make_where_clause().predicates.push(
1572                        parse_quote_spanned! { ty.span() =>
1573                            (#ty, __I::Extra): #bound
1574                        },
1575                    );
1576                } else {
1577                    generics.make_where_clause().predicates.push(
1578                        parse_quote_spanned! { ty.span() =>
1579                            #ty: #tr
1580                        },
1581                    );
1582                }
1583            }
1584        }
1585        Data::Enum(data) => {
1586            for v in data.variants.iter() {
1587                'field: for f in v.fields.iter() {
1588                    let ty = &f.ty;
1589                    let mut b = None;
1590                    for attr in &f.attrs {
1591                        if attr_str(attr).as_deref() == Some("parse") {
1592                            let ParseArgs {
1593                                bound, unchecked, ..
1594                            } = attr.parse_args::<ParseArgs>()?;
1595                            if unchecked {
1596                                continue 'field;
1597                            }
1598                            if let Some(bound) = bound {
1599                                b = Some(bound);
1600                            }
1601                        }
1602                    }
1603                    if let Some(bound) = b {
1604                        generics.make_where_clause().predicates.push(
1605                            parse_quote_spanned! { ty.span() =>
1606                                (#ty, __I::Extra): #bound
1607                            },
1608                        );
1609                    } else {
1610                        generics.make_where_clause().predicates.push(
1611                            parse_quote_spanned! { ty.span() =>
1612                                #ty: #tr
1613                            },
1614                        );
1615                    }
1616                }
1617            }
1618        }
1619        Data::Union(data) => {
1620            return Err(Error::new_spanned(
1621                data.union_token,
1622                "`union`s are not supported",
1623            ));
1624        }
1625    }
1626    generics.params.push(if recursive {
1627        parse_quote!(__I: ::object_rainbow::PointInput<
1628            Extra: ::core::marker::Send + ::core::marker::Sync
1629        >)
1630    } else {
1631        parse_quote!(__I: ::object_rainbow::ParseInput)
1632    });
1633    Ok(generics)
1634}
1635
1636fn fields_parse_inline(fields: &syn::Fields) -> proc_macro2::TokenStream {
1637    match fields {
1638        syn::Fields::Named(fields) => {
1639            let parse = fields.named.iter().map(|f| {
1640                let i = f.ident.as_ref().unwrap();
1641                quote_spanned! { f.ty.span() =>
1642                    #i: input.parse_inline()?
1643                }
1644            });
1645            quote! { { #(#parse),* } }
1646        }
1647        syn::Fields::Unnamed(fields) => {
1648            let parse = fields.unnamed.iter().map(|f| {
1649                quote_spanned! { f.ty.span() =>
1650                    input.parse_inline()?
1651                }
1652            });
1653            quote! { (#(#parse),*) }
1654        }
1655        syn::Fields::Unit => quote! {},
1656    }
1657}
1658
1659fn gen_parse_inline(data: &Data) -> proc_macro2::TokenStream {
1660    match data {
1661        Data::Struct(data) => {
1662            let arm = fields_parse_inline(&data.fields);
1663            quote! { Ok(Self #arm) }
1664        }
1665        Data::Enum(data) => {
1666            let parse_inline = data.variants.iter().map(|v| {
1667                let ident = &v.ident;
1668                let arm = fields_parse_inline(&v.fields);
1669                quote! {
1670                    <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
1671                }
1672            });
1673            quote! {
1674                Ok(match input.parse_inline()? {
1675                    #(#parse_inline)*
1676                })
1677            }
1678        }
1679        Data::Union(data) => {
1680            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1681        }
1682    }
1683}
1684
1685#[proc_macro_derive(ParseAsInline)]
1686pub fn derive_parse_as_inline(input: TokenStream) -> TokenStream {
1687    let input = parse_macro_input!(input as DeriveInput);
1688    let name = input.ident;
1689    let generics = input.generics.clone();
1690    let (_, ty_generics, _) = generics.split_for_impl();
1691    let generics = match bounds_parse_as_inline(input.generics, &name) {
1692        Ok(g) => g,
1693        Err(e) => return e.into_compile_error().into(),
1694    };
1695    let (impl_generics, _, where_clause) = generics.split_for_impl();
1696    let target = parse_for(&name, &input.attrs);
1697    let output = quote! {
1698        #[automatically_derived]
1699        impl #impl_generics ::object_rainbow::Parse<__I> for #target #ty_generics #where_clause {
1700            fn parse(input: __I) -> ::object_rainbow::Result<Self> {
1701                ::object_rainbow::ParseInline::<__I>::parse_as_inline(input)
1702            }
1703        }
1704    };
1705    TokenStream::from(output)
1706}
1707
1708fn bounds_parse_as_inline(mut generics: Generics, name: &Ident) -> syn::Result<Generics> {
1709    generics
1710        .make_where_clause()
1711        .predicates
1712        .push(parse_quote_spanned! { name.span() =>
1713            Self: ::object_rainbow::ParseInline::<__I>
1714        });
1715    generics
1716        .params
1717        .push(parse_quote!(__I: ::object_rainbow::ParseInput));
1718    Ok(generics)
1719}
1720
1721fn parse_path(attr: &Attribute) -> syn::Result<Type> {
1722    attr.parse_args::<LitStr>()?.parse()
1723}
1724
1725fn attr_str(attr: &Attribute) -> Option<String> {
1726    Some(attr.path().get_ident()?.to_string())
1727}
1728
1729#[proc_macro_derive(Enum, attributes(enumtag))]
1730pub fn derive_enum(input: TokenStream) -> TokenStream {
1731    let input = parse_macro_input!(input as DeriveInput);
1732    let name = input.ident;
1733    let generics = input.generics.clone();
1734    let (_, ty_generics, _) = generics.split_for_impl();
1735    let generics = input.generics;
1736    let variants = gen_variants(&input.data);
1737    let variant_count = gen_variant_count(&input.data);
1738    let to_tag = gen_to_tag(&input.data);
1739    let from_tag = gen_from_tag(&input.data);
1740    let kind = gen_kind(&input.data);
1741    let (impl_generics, _, where_clause) = generics.split_for_impl();
1742    let mut errors = Vec::new();
1743    let mut enumtag = None;
1744    for attr in &input.attrs {
1745        if attr_str(attr).as_deref() == Some("enumtag") {
1746            match parse_path(attr) {
1747                Ok(path) => {
1748                    if enumtag.is_some() {
1749                        errors.push(Error::new_spanned(path, "duplicate tag"));
1750                    } else {
1751                        enumtag = Some(path);
1752                    }
1753                }
1754                Err(e) => errors.push(e),
1755            }
1756        }
1757    }
1758    let enumtag = enumtag
1759        .unwrap_or_else(|| parse_quote!(::object_rainbow::numeric::Le<::core::num::NonZero<u8>>));
1760    let errors = errors.into_iter().map(|e| e.into_compile_error());
1761    let target = parse_for(&name, &input.attrs);
1762    let output = quote! {
1763        const _: () = {
1764            #(#errors)*
1765
1766            use ::object_rainbow::enumkind::EnumKind;
1767
1768            #[derive(Clone, Copy, ::object_rainbow::ParseAsInline)]
1769            pub enum __Kind {
1770                #variants
1771            }
1772
1773            #[automatically_derived]
1774            impl ::object_rainbow::enumkind::EnumKind for __Kind {
1775                type Tag = ::object_rainbow::enumkind::EnumTag<
1776                    #enumtag,
1777                    #variant_count,
1778                >;
1779
1780                fn to_tag(self) -> Self::Tag {
1781                    #to_tag
1782                }
1783
1784                fn from_tag(tag: Self::Tag) -> Self {
1785                    #from_tag
1786                }
1787            }
1788
1789            impl<I: ::object_rainbow::ParseInput> ::object_rainbow::ParseInline<I> for __Kind {
1790                fn parse_inline(input: &mut I) -> ::object_rainbow::Result<Self> {
1791                    Ok(::object_rainbow::enumkind::EnumKind::from_tag(input.parse_inline()?))
1792                }
1793            }
1794
1795            #[automatically_derived]
1796            impl #impl_generics ::object_rainbow::Enum for #target #ty_generics #where_clause {
1797                type Kind = __Kind;
1798
1799                fn kind(&self) -> Self::Kind {
1800                    #kind
1801                }
1802            }
1803        };
1804    };
1805    TokenStream::from(output)
1806}
1807
1808fn gen_variants(data: &Data) -> proc_macro2::TokenStream {
1809    match data {
1810        Data::Struct(data) => {
1811            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1812        }
1813        Data::Enum(data) => {
1814            let variants = data.variants.iter().map(|v| &v.ident);
1815            quote! { #(#variants),* }
1816        }
1817        Data::Union(data) => {
1818            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1819        }
1820    }
1821}
1822
1823fn gen_variant_count(data: &Data) -> proc_macro2::TokenStream {
1824    match data {
1825        Data::Struct(data) => {
1826            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1827        }
1828        Data::Enum(data) => {
1829            let variant_count = data.variants.len();
1830            quote! { #variant_count }
1831        }
1832        Data::Union(data) => {
1833            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1834        }
1835    }
1836}
1837
1838fn gen_to_tag(data: &Data) -> proc_macro2::TokenStream {
1839    match data {
1840        Data::Struct(data) => {
1841            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1842        }
1843        Data::Enum(data) => {
1844            let to_tag = data.variants.iter().enumerate().map(|(i, v)| {
1845                let ident = &v.ident;
1846                quote_spanned! { ident.span() =>
1847                    Self::#ident => ::object_rainbow::enumkind::EnumTag::from_const::<#i>(),
1848                }
1849            });
1850            quote! {
1851                match self {
1852                    #(#to_tag)*
1853                }
1854            }
1855        }
1856        Data::Union(data) => {
1857            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1858        }
1859    }
1860}
1861
1862fn gen_from_tag(data: &Data) -> proc_macro2::TokenStream {
1863    match data {
1864        Data::Struct(data) => {
1865            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1866        }
1867        Data::Enum(data) => {
1868            let from_tag = data.variants.iter().enumerate().map(|(i, v)| {
1869                let ident = &v.ident;
1870                quote_spanned! { ident.span() =>
1871                    #i => Self::#ident,
1872                }
1873            });
1874            quote! {
1875                match tag.to_usize() {
1876                    #(#from_tag)*
1877                    _ => unreachable!(),
1878                }
1879            }
1880        }
1881        Data::Union(data) => {
1882            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1883        }
1884    }
1885}
1886
1887fn gen_kind(data: &Data) -> proc_macro2::TokenStream {
1888    match data {
1889        Data::Struct(data) => {
1890            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1891        }
1892        Data::Enum(data) => {
1893            let variants = data.variants.iter().map(|v| {
1894                let ident = &v.ident;
1895                quote_spanned! { ident.span() =>
1896                    Self::#ident {..} => __Kind::#ident,
1897                }
1898            });
1899            quote! {
1900                match self {
1901                    #(#variants)*
1902                }
1903            }
1904        }
1905        Data::Union(data) => {
1906            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1907        }
1908    }
1909}
1910
1911#[proc_macro_derive(MaybeHasNiche)]
1912pub fn derive_maybe_has_niche(input: TokenStream) -> TokenStream {
1913    let input = parse_macro_input!(input as DeriveInput);
1914    let name = input.ident;
1915    let mn_array = gen_mn_array(&input.data);
1916    let (_, ty_generics, _) = input.generics.split_for_impl();
1917    let generics = match bounds_maybe_has_niche(input.generics.clone(), &input.data) {
1918        Ok(g) => g,
1919        Err(e) => return e.into_compile_error().into(),
1920    };
1921    let (impl_generics, _, where_clause) = generics.split_for_impl();
1922    let target = parse_for(&name, &input.attrs);
1923    let output = quote! {
1924        const _: () = {
1925            use ::object_rainbow::typenum::tarr;
1926
1927            #[automatically_derived]
1928            impl #impl_generics ::object_rainbow::MaybeHasNiche for #target #ty_generics #where_clause {
1929                type MnArray = #mn_array;
1930            }
1931        };
1932    };
1933    TokenStream::from(output)
1934}
1935
1936fn bounds_maybe_has_niche(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
1937    match data {
1938        Data::Struct(data) => {
1939            for f in data.fields.iter() {
1940                let ty = &f.ty;
1941                generics
1942                    .make_where_clause()
1943                    .predicates
1944                    .push(parse_quote_spanned! { ty.span() =>
1945                        #ty: ::object_rainbow::MaybeHasNiche<
1946                            MnArray: ::object_rainbow::MnArray<
1947                                MaybeNiche: ::object_rainbow::MaybeNiche
1948                            >
1949                        >
1950                    });
1951            }
1952        }
1953        Data::Enum(data) => {
1954            generics.params.push(parse_quote!(
1955                __N: ::object_rainbow::typenum::Unsigned
1956            ));
1957            for (i, v) in data.variants.iter().enumerate() {
1958                let mn_array = fields_mn_array(&v.fields, Some(i));
1959                generics
1960                    .make_where_clause()
1961                    .predicates
1962                    .push(parse_quote_spanned! { v.span() =>
1963                        #mn_array: ::object_rainbow::MnArray<
1964                            MaybeNiche: ::object_rainbow::NicheOr<N = __N>
1965                        >
1966                    });
1967                for f in v.fields.iter() {
1968                    let ty = &f.ty;
1969                    generics.make_where_clause().predicates.push(
1970                        parse_quote_spanned! { ty.span() =>
1971                            #ty: ::object_rainbow::MaybeHasNiche<
1972                                MnArray: ::object_rainbow::MnArray<
1973                                    MaybeNiche: ::object_rainbow::MaybeNiche
1974                                >
1975                            >
1976                        },
1977                    );
1978                }
1979            }
1980        }
1981        Data::Union(data) => {
1982            return Err(Error::new_spanned(
1983                data.union_token,
1984                "`union`s are not supported",
1985            ));
1986        }
1987    }
1988    Ok(generics)
1989}
1990
1991fn fields_mn_array(fields: &syn::Fields, variant: Option<usize>) -> proc_macro2::TokenStream {
1992    let mn_array = fields.iter().map(|f| {
1993        let ty = &f.ty;
1994        quote! {
1995            <
1996                <
1997                    #ty
1998                    as
1999                    ::object_rainbow::MaybeHasNiche
2000                >::MnArray
2001                as
2002                ::object_rainbow::MnArray
2003            >::MaybeNiche
2004        }
2005    });
2006    if let Some(variant) = variant {
2007        let kind_niche = quote! {
2008            ::object_rainbow::AutoEnumNiche<Self, #variant>
2009        };
2010        quote! { tarr![#kind_niche, ::object_rainbow::NoNiche<::object_rainbow::HackNiche<#variant>>, #(#mn_array),*] }
2011    } else {
2012        quote! { tarr![#(#mn_array),*] }
2013    }
2014}
2015
2016fn gen_mn_array(data: &Data) -> proc_macro2::TokenStream {
2017    match data {
2018        Data::Struct(data) => fields_mn_array(&data.fields, None),
2019        Data::Enum(data) => {
2020            let mn_array = data.variants.iter().enumerate().map(|(i, v)| {
2021                let mn_array = fields_mn_array(&v.fields, Some(i));
2022                quote! { <#mn_array as ::object_rainbow::MnArray>::MaybeNiche }
2023            });
2024            quote! {
2025                ::object_rainbow::NicheFoldOrArray<tarr![#(#mn_array),*]>
2026            }
2027        }
2028        Data::Union(data) => {
2029            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
2030        }
2031    }
2032}