Skip to main content

object_rainbow_derive/
lib.rs

1//! `#[derive(...)]`s for [`object-rainbow`](<https://docs.rs/object-rainbow>).
2
3use std::collections::BTreeSet;
4
5use darling::{FromMeta, util::SpannedValue};
6use proc_macro::TokenStream;
7use proc_macro2::Span;
8use quote::{ToTokens, quote, quote_spanned};
9use syn::{
10    Attribute, Data, DeriveInput, Error, Expr, FnArg, GenericParam, Generics, Ident, ImplItem,
11    Item, ItemTrait, LitStr, TraitItem, Type, WherePredicate, parse::Parse, parse_macro_input,
12    parse_quote, parse_quote_spanned, spanned::Spanned, token::Comma,
13};
14
15use self::contains_generics::{GContext, type_contains_generics};
16
17mod contains_generics;
18
19/// leave all hope
20fn bounds_g(generics: &Generics) -> BTreeSet<Ident> {
21    generics
22        .params
23        .iter()
24        .filter_map(|param| match param {
25            GenericParam::Lifetime(_) => None,
26            GenericParam::Type(param) => Some(&param.ident),
27            GenericParam::Const(param) => Some(&param.ident),
28        })
29        .cloned()
30        .collect()
31}
32
33#[derive(Debug, FromMeta)]
34#[darling(derive_syn_parse)]
35struct RainbowArgs {
36    #[darling(default)]
37    remote: Option<Type>,
38    #[darling(default)]
39    untagged: SpannedValue<bool>,
40}
41
42fn parse_for(name: &Ident, attrs: &[Attribute]) -> proc_macro2::TokenStream {
43    for attr in attrs {
44        if attr_str(attr).as_deref() == Some("rainbow") {
45            match attr.parse_args::<RainbowArgs>() {
46                Ok(RainbowArgs { remote, .. }) => {
47                    if let Some(remote) = remote {
48                        return remote.to_token_stream();
49                    }
50                }
51                Err(e) => return e.into_compile_error(),
52            }
53        }
54    }
55    name.to_token_stream()
56}
57
58fn parse_untagged(attrs: &[Attribute]) -> syn::Result<Option<SpannedValue<bool>>> {
59    let mut u = None;
60    for attr in attrs {
61        if attr_str(attr).as_deref() == Some("rainbow") {
62            let RainbowArgs { untagged, .. } = attr.parse_args()?;
63            if *untagged {
64                u = Some(untagged);
65            }
66        }
67    }
68    Ok(u)
69}
70
71/// ```rust
72/// use object_rainbow::{InlineOutput, ToOutput};
73///
74/// #[derive(ToOutput)]
75/// struct Three<A, B, C> {
76///     a: A,
77///     b: B,
78///     c: C,
79/// }
80///
81/// object_rainbow::assert_impl!(
82///     impl<A, B, C> ToOutput for Three<A, B, C>
83///     where
84///         A: InlineOutput,
85///         B: InlineOutput,
86///         C: ToOutput,
87///     {}
88/// );
89/// ```
90#[proc_macro_derive(ToOutput, attributes(rainbow, output))]
91pub fn derive_to_output(input: TokenStream) -> TokenStream {
92    let input = parse_macro_input!(input as DeriveInput);
93    let name = input.ident;
94    let generics = match bounds_to_output(input.generics, &input.data, &input.attrs) {
95        Ok(g) => g,
96        Err(e) => return e.into_compile_error().into(),
97    };
98    let to_output = gen_to_output(&input.data, &input.attrs);
99    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
100    let target = parse_for(&name, &input.attrs);
101    let output = quote! {
102        #[automatically_derived]
103        impl #impl_generics ::object_rainbow::ToOutput for #target #ty_generics #where_clause {
104            fn to_output(&self, output: &mut (impl ?::core::marker::Sized + ::object_rainbow::Output)) {
105                #to_output
106            }
107        }
108    };
109    TokenStream::from(output)
110}
111
112#[derive(Debug, FromMeta)]
113#[darling(derive_syn_parse)]
114struct ContainerOutputArgs {
115    #[darling(default)]
116    unchecked: bool,
117    #[darling(default)]
118    bound: Option<LitStr>,
119    #[darling(default)]
120    auto: Option<Type>,
121}
122
123#[derive(Debug, FromMeta)]
124#[darling(derive_syn_parse)]
125struct FieldOutputArgs {
126    #[darling(default)]
127    unchecked: bool,
128}
129
130fn parse_output_bounds(attrs: &[Attribute]) -> syn::Result<(bool, Vec<WherePredicate>, Vec<Type>)> {
131    let mut u = false;
132    let mut wheres = Vec::new();
133    let mut a = Vec::new();
134    for attr in attrs {
135        if attr_str(attr).as_deref() == Some("output") {
136            let ContainerOutputArgs {
137                unchecked,
138                bound,
139                auto,
140            } = attr.parse_args()?;
141            if unchecked {
142                u = true;
143            }
144            if let Some(bound) = bound {
145                wheres.push(bound.parse()?);
146            }
147            a.extend(auto);
148        }
149    }
150    Ok((u, wheres, a))
151}
152
153fn bounds_to_output(
154    mut generics: Generics,
155    data: &Data,
156    attrs: &[Attribute],
157) -> syn::Result<Generics> {
158    let (u, wheres, auto) = parse_output_bounds(attrs)?;
159    let g = &bounds_g(&generics);
160    match data {
161        Data::Struct(data) => {
162            let last_at = data.fields.len().saturating_sub(1);
163            'field: for (i, f) in data.fields.iter().enumerate() {
164                let last = i == last_at;
165                let ty = &f.ty;
166                let tr = if last {
167                    quote!(::object_rainbow::ToOutput)
168                } else {
169                    quote!(::object_rainbow::InlineOutput)
170                };
171                for attr in &f.attrs {
172                    if attr_str(attr).as_deref() == Some("output") {
173                        let FieldOutputArgs { unchecked, .. } = attr.parse_args()?;
174                        if unchecked {
175                            continue 'field;
176                        }
177                    }
178                }
179                if u {
180                    continue 'field;
181                }
182                if !last || type_contains_generics(GContext { g, always: false }, ty) {
183                    generics.make_where_clause().predicates.push(
184                        parse_quote_spanned! { ty.span() =>
185                            #ty: #tr
186                        },
187                    );
188                }
189            }
190        }
191        Data::Enum(data) => {
192            for v in data.variants.iter() {
193                let last_at = v.fields.len().saturating_sub(1);
194                'field: for (i, f) in v.fields.iter().enumerate() {
195                    let last = i == last_at;
196                    let ty = &f.ty;
197                    let tr = if last {
198                        quote!(::object_rainbow::ToOutput)
199                    } else {
200                        quote!(::object_rainbow::InlineOutput)
201                    };
202                    for attr in &f.attrs {
203                        if attr_str(attr).as_deref() == Some("output") {
204                            let FieldOutputArgs { unchecked, .. } = attr.parse_args()?;
205                            if unchecked {
206                                continue 'field;
207                            }
208                        }
209                    }
210                    if u {
211                        continue 'field;
212                    }
213                    if !last || type_contains_generics(GContext { g, always: false }, ty) {
214                        generics.make_where_clause().predicates.push(
215                            parse_quote_spanned! { ty.span() =>
216                                #ty: #tr
217                            },
218                        );
219                    }
220                }
221            }
222        }
223        Data::Union(data) => {
224            return Err(Error::new_spanned(
225                data.union_token,
226                "`union`s are not supported",
227            ));
228        }
229    }
230    for bound in wheres {
231        generics.make_where_clause().predicates.push(bound);
232    }
233    for auto in auto {
234        generics
235            .make_where_clause()
236            .predicates
237            .push(parse_quote_spanned! { auto.span() =>
238                #auto: ::object_rainbow::ToOutput
239            });
240    }
241    Ok(generics)
242}
243
244fn fields_to_output(fields: &syn::Fields) -> proc_macro2::TokenStream {
245    match fields {
246        syn::Fields::Named(fields) => {
247            let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
248            let to_output = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
249                quote_spanned! { f.ty.span() =>
250                    #i.to_output(output)
251                }
252            });
253            quote! {
254                { #(#let_self),* } => {
255                    #(#to_output);*
256                }
257            }
258        }
259        syn::Fields::Unnamed(fields) => {
260            let let_self = fields
261                .unnamed
262                .iter()
263                .enumerate()
264                .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
265            let to_output = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
266                quote_spanned! { f.ty.span() =>
267                    #i.to_output(output)
268                }
269            });
270            quote! {
271                (#(#let_self),*) => {
272                    #(#to_output);*
273                }
274            }
275        }
276        syn::Fields::Unit => quote! {
277            => {}
278        },
279    }
280}
281
282fn gen_to_output(data: &Data, attrs: &[Attribute]) -> proc_macro2::TokenStream {
283    let untagged = match parse_untagged(attrs) {
284        Ok(untagged) => untagged,
285        Err(e) => return e.into_compile_error(),
286    };
287    match data {
288        Data::Struct(data) => {
289            let arm = fields_to_output(&data.fields);
290            quote! {
291                match self {
292                    Self #arm
293                }
294            }
295        }
296        Data::Enum(data) => {
297            if data.variants.is_empty() {
298                return quote! {};
299            }
300            let to_output = data.variants.iter().map(|v| {
301                let ident = &v.ident;
302                let arm = fields_to_output(&v.fields);
303                quote! { Self::#ident #arm }
304            });
305            let tagged = if untagged.is_none() {
306                quote! {
307                    let kind = ::object_rainbow::Enum::kind(self);
308                    let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
309                    tag.to_output(output);
310                }
311            } else {
312                quote! {}
313            };
314            quote! {
315                #tagged
316                match self {
317                    #(#to_output)*
318                }
319            }
320        }
321        Data::Union(data) => {
322            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
323        }
324    }
325}
326
327/// ```rust
328/// use object_rainbow::{InlineOutput, ToOutput};
329///
330/// #[derive(ToOutput, InlineOutput)]
331/// struct Three<A, B, C> {
332///     a: A,
333///     b: B,
334///     c: C,
335/// }
336///
337/// object_rainbow::assert_impl!(
338///     impl<A, B, C> InlineOutput for Three<A, B, C>
339///     where
340///         A: InlineOutput,
341///         B: InlineOutput,
342///         C: InlineOutput,
343///     {}
344/// );
345/// ```
346#[proc_macro_derive(InlineOutput)]
347pub fn derive_inline_output(input: TokenStream) -> TokenStream {
348    let input = parse_macro_input!(input as DeriveInput);
349    let name = input.ident;
350    let generics = match bounds_inline_output(input.generics, &input.data, &input.attrs) {
351        Ok(g) => g,
352        Err(e) => return e.into_compile_error().into(),
353    };
354    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
355    let target = parse_for(&name, &input.attrs);
356    let output = quote! {
357        #[automatically_derived]
358        impl #impl_generics ::object_rainbow::InlineOutput for #target #ty_generics #where_clause {}
359    };
360    TokenStream::from(output)
361}
362
363fn bounds_inline_output(
364    mut generics: Generics,
365    data: &Data,
366    attrs: &[Attribute],
367) -> syn::Result<Generics> {
368    let (u, wheres, auto) = parse_output_bounds(attrs)?;
369    match data {
370        Data::Struct(data) => {
371            'field: for f in data.fields.iter() {
372                let ty = &f.ty;
373                for attr in &f.attrs {
374                    if attr_str(attr).as_deref() == Some("output") {
375                        let FieldOutputArgs { unchecked, .. } = attr.parse_args()?;
376                        if unchecked {
377                            continue 'field;
378                        }
379                    }
380                }
381                if u {
382                    continue 'field;
383                }
384                generics
385                    .make_where_clause()
386                    .predicates
387                    .push(parse_quote_spanned! { ty.span() =>
388                        #ty: ::object_rainbow::InlineOutput
389                    });
390            }
391        }
392        Data::Enum(data) => {
393            for v in data.variants.iter() {
394                'field: for f in v.fields.iter() {
395                    let ty = &f.ty;
396                    for attr in &f.attrs {
397                        if attr_str(attr).as_deref() == Some("output") {
398                            let FieldOutputArgs { unchecked, .. } = attr.parse_args()?;
399                            if unchecked {
400                                continue 'field;
401                            }
402                        }
403                    }
404                    if u {
405                        continue 'field;
406                    }
407                    generics.make_where_clause().predicates.push(
408                        parse_quote_spanned! { ty.span() =>
409                            #ty: ::object_rainbow::InlineOutput
410                        },
411                    );
412                }
413            }
414        }
415        Data::Union(data) => {
416            return Err(Error::new_spanned(
417                data.union_token,
418                "`union`s are not supported",
419            ));
420        }
421    }
422    for bound in wheres {
423        generics.make_where_clause().predicates.push(bound);
424    }
425    for auto in auto {
426        generics
427            .make_where_clause()
428            .predicates
429            .push(parse_quote_spanned! { auto.span() =>
430                #auto: ::object_rainbow::InlineOutput
431            });
432    }
433    Ok(generics)
434}
435
436#[proc_macro_derive(ByteOrd)]
437pub fn derive_byte_ord(input: TokenStream) -> TokenStream {
438    let input = parse_macro_input!(input as DeriveInput);
439    let name = input.ident;
440    let generics = match bounds_byte_ord(input.generics, &input.data) {
441        Ok(g) => g,
442        Err(e) => return e.into_compile_error().into(),
443    };
444    let bytes_cmp = gen_bytes_cmp(&input.data);
445    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
446    let target = parse_for(&name, &input.attrs);
447    let output = quote! {
448        #[automatically_derived]
449        impl #impl_generics ::object_rainbow::ByteOrd for #target #ty_generics #where_clause {
450            #[allow(nonstandard_style)]
451            fn bytes_cmp(&self, other: &Self) -> ::core::cmp::Ordering {
452                #bytes_cmp
453            }
454        }
455    };
456    TokenStream::from(output)
457}
458
459fn bounds_byte_ord(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
460    let g = &bounds_g(&generics);
461    match data {
462        Data::Struct(data) => {
463            'field: for f in data.fields.iter() {
464                let ty = &f.ty;
465                let tr = quote!(::object_rainbow::ByteOrd);
466                for attr in &f.attrs {
467                    if attr_str(attr).as_deref() == Some("output") {
468                        let FieldOutputArgs { unchecked, .. } = attr.parse_args()?;
469                        if unchecked {
470                            continue 'field;
471                        }
472                    }
473                }
474                if type_contains_generics(GContext { g, always: false }, ty) {
475                    generics.make_where_clause().predicates.push(
476                        parse_quote_spanned! { ty.span() =>
477                            #ty: #tr
478                        },
479                    );
480                }
481            }
482        }
483        Data::Enum(data) => {
484            for v in data.variants.iter() {
485                'field: for f in v.fields.iter() {
486                    let ty = &f.ty;
487                    let tr = quote!(::object_rainbow::ByteOrd);
488                    for attr in &f.attrs {
489                        if attr_str(attr).as_deref() == Some("output") {
490                            let FieldOutputArgs { unchecked, .. } = attr.parse_args()?;
491                            if unchecked {
492                                continue 'field;
493                            }
494                        }
495                    }
496                    if type_contains_generics(GContext { g, always: false }, ty) {
497                        generics.make_where_clause().predicates.push(
498                            parse_quote_spanned! { ty.span() =>
499                                #ty: #tr
500                            },
501                        );
502                    }
503                }
504            }
505            generics.make_where_clause().predicates.push(parse_quote! {
506                <
507                    <Self as ::object_rainbow::Enum>::Kind
508                    as
509                ::object_rainbow::enumkind::EnumKind
510                >::Tag:
511                    ::object_rainbow::ByteOrd + ::object_rainbow::InlineOutput
512            });
513        }
514        Data::Union(data) => {
515            return Err(Error::new_spanned(
516                data.union_token,
517                "`union`s are not supported",
518            ));
519        }
520    }
521    generics.make_where_clause().predicates.push(parse_quote! {
522        Self: ::core::cmp::PartialOrd + ::object_rainbow::ToOutput
523    });
524    Ok(generics)
525}
526
527fn let_self_other(fields: &syn::Fields, prefix: &str) -> proc_macro2::TokenStream {
528    match fields {
529        syn::Fields::Named(fields) => {
530            let fragments = fields.named.iter().map(|f| {
531                let ident = f.ident.as_ref().unwrap();
532                let prefixed_ident = Ident::new(&format!("{prefix}{ident}"), f.ty.span());
533                let colon = f.colon_token.unwrap();
534                quote! { #ident #colon #prefixed_ident }
535            });
536            quote! { {#(#fragments),*} }
537        }
538        syn::Fields::Unnamed(fields) => {
539            let fragments = fields.unnamed.iter().enumerate().map(|(i, f)| {
540                let prefixed_ident = Ident::new(&format!("{prefix}{i}"), f.ty.span());
541                quote! { #prefixed_ident }
542            });
543            quote! { (#(#fragments),*) }
544        }
545        syn::Fields::Unit => quote! {},
546    }
547}
548
549fn bytes_cmp_self_other(fields: &syn::Fields) -> proc_macro2::TokenStream {
550    let then = match fields {
551        syn::Fields::Named(fields) => {
552            let fragments = fields.named.iter().map(|f| {
553                let ident = f.ident.as_ref().unwrap();
554                let self_ident = Ident::new(&format!("__self_{ident}"), f.ty.span());
555                let other_ident = Ident::new(&format!("__other_{ident}"), f.ty.span());
556                quote! { .then_with(|| ::object_rainbow::ByteOrd::bytes_cmp(#self_ident, #other_ident)) }
557            });
558            quote! { #(#fragments)* }
559        }
560        syn::Fields::Unnamed(fields) => {
561            let fragments = fields.unnamed.iter().enumerate().map(|(i, f)| {
562                let self_ident = Ident::new(&format!("__self_{i}"), f.ty.span());
563                let other_ident = Ident::new(&format!("__other_{i}"), f.ty.span());
564                quote! { .then_with(|| ::object_rainbow::ByteOrd::bytes_cmp(#self_ident, #other_ident)) }
565            });
566            quote! { #(#fragments)* }
567        }
568        syn::Fields::Unit => quote! {},
569    };
570    quote! { ::core::cmp::Ordering::Equal #then }
571}
572
573fn gen_bytes_cmp(data: &Data) -> proc_macro2::TokenStream {
574    match data {
575        Data::Struct(data) => {
576            let let_self = let_self_other(&data.fields, "__self_");
577            let let_other = let_self_other(&data.fields, "__other_");
578            let bytes_cmp = bytes_cmp_self_other(&data.fields);
579            quote! {
580                match (self, other) {
581                    (Self #let_self, Self #let_other) => #bytes_cmp,
582                }
583            }
584        }
585        Data::Enum(data) => {
586            let arms = data.variants.iter().map(|variant| {
587                let ident = &variant.ident;
588                let let_self = let_self_other(&variant.fields, "__self_");
589                let let_other = let_self_other(&variant.fields, "__other_");
590                let bytes_cmp = bytes_cmp_self_other(&variant.fields);
591                quote! {
592                    (Self::#ident #let_self, Self::#ident #let_other) => #bytes_cmp,
593                    (Self::#ident { .. }, _) => ::core::cmp::Ordering::Less,
594                    (_, Self::#ident { .. }) => ::core::cmp::Ordering::Greater,
595                }
596            });
597            quote! {
598                match (self, other) {
599                    #(#arms)*
600                }
601            }
602        }
603        Data::Union(data) => {
604            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
605        }
606    }
607}
608
609/// ```rust
610/// use object_rainbow::ListHashes;
611///
612/// #[derive(ListHashes)]
613/// struct Three<A, B, C> {
614///     a: A,
615///     b: B,
616///     c: C,
617/// }
618///
619/// object_rainbow::assert_impl!(
620///     impl<A, B, C> ListHashes for Three<A, B, C>
621///     where
622///         A: ListHashes,
623///         B: ListHashes,
624///         C: ListHashes,
625///     {}
626/// );
627/// ```
628#[proc_macro_derive(ListHashes, attributes(topology, rainbow, hashes))]
629pub fn derive_list_hashes(input: TokenStream) -> TokenStream {
630    let input = parse_macro_input!(input as DeriveInput);
631    let name = input.ident;
632    let generics = input.generics.clone();
633    let (_, ty_generics, _) = generics.split_for_impl();
634    let generics = match bounds_list_hashes(input.generics, &input.data, &input.attrs) {
635        Ok(g) => g,
636        Err(e) => return e.into_compile_error().into(),
637    };
638    let list_hashes = gen_list_hashes(&input.data, &input.attrs);
639    let (impl_generics, _, where_clause) = generics.split_for_impl();
640    let target = parse_for(&name, &input.attrs);
641    let output = quote! {
642        #[automatically_derived]
643        impl #impl_generics ::object_rainbow::ListHashes for #target #ty_generics #where_clause {
644            fn list_hashes(&self, visitor: &mut (impl ?::core::marker::Sized + FnMut(::object_rainbow::Hash))) {
645                #list_hashes
646            }
647        }
648    };
649    TokenStream::from(output)
650}
651
652#[derive(Debug, FromMeta)]
653#[darling(derive_syn_parse)]
654struct ContainerHashesArgs {
655    #[darling(default)]
656    bound: Option<LitStr>,
657}
658
659#[derive(Debug, FromMeta)]
660#[darling(derive_syn_parse)]
661struct FieldHashesArgs {
662    #[darling(default)]
663    unchecked: bool,
664}
665
666fn parse_hashes_bounds(attrs: &[Attribute]) -> syn::Result<Vec<WherePredicate>> {
667    let mut wheres = Vec::new();
668    for attr in attrs {
669        if attr_str(attr).as_deref() == Some("hashes") {
670            let ContainerHashesArgs { bound } = attr.parse_args()?;
671            if let Some(bound) = bound {
672                wheres.push(bound.parse()?);
673            }
674        }
675    }
676    Ok(wheres)
677}
678
679fn bounds_list_hashes(
680    mut generics: Generics,
681    data: &Data,
682    attrs: &[Attribute],
683) -> syn::Result<Generics> {
684    let wheres = parse_hashes_bounds(attrs)?;
685    let g = &bounds_g(&generics);
686    match data {
687        Data::Struct(data) => {
688            'field: for f in data.fields.iter() {
689                let ty = &f.ty;
690                for attr in &f.attrs {
691                    if attr_str(attr).as_deref() == Some("output") {
692                        let FieldHashesArgs { unchecked, .. } = attr.parse_args()?;
693                        if unchecked {
694                            continue 'field;
695                        }
696                    }
697                }
698                if type_contains_generics(GContext { g, always: false }, ty) {
699                    generics.make_where_clause().predicates.push(
700                        parse_quote_spanned! { ty.span() =>
701                            #ty: ::object_rainbow::ListHashes
702                        },
703                    );
704                }
705            }
706        }
707        Data::Enum(data) => {
708            for v in data.variants.iter() {
709                'field: for f in v.fields.iter() {
710                    let ty = &f.ty;
711                    for attr in &f.attrs {
712                        if attr_str(attr).as_deref() == Some("output") {
713                            let FieldHashesArgs { unchecked, .. } = attr.parse_args()?;
714                            if unchecked {
715                                continue 'field;
716                            }
717                        }
718                    }
719                    if type_contains_generics(GContext { g, always: false }, ty) {
720                        generics.make_where_clause().predicates.push(
721                            parse_quote_spanned! { ty.span() =>
722                                #ty: ::object_rainbow::ListHashes
723                            },
724                        );
725                    }
726                }
727            }
728        }
729        Data::Union(data) => {
730            return Err(Error::new_spanned(
731                data.union_token,
732                "`union`s are not supported",
733            ));
734        }
735    }
736    for bound in wheres {
737        generics.make_where_clause().predicates.push(bound);
738    }
739    Ok(generics)
740}
741
742fn fields_list_hashes(fields: &syn::Fields) -> proc_macro2::TokenStream {
743    match fields {
744        syn::Fields::Named(fields) => {
745            let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
746            let list_hashes = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
747                quote_spanned! { f.ty.span() =>
748                    #i.list_hashes(visitor)
749                }
750            });
751            quote! {
752                { #(#let_self),* } => {
753                    #(#list_hashes);*
754                }
755            }
756        }
757        syn::Fields::Unnamed(fields) => {
758            let let_self = fields
759                .unnamed
760                .iter()
761                .enumerate()
762                .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
763            let list_hashes = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
764                quote_spanned! { f.ty.span() =>
765                    #i.list_hashes(visitor)
766                }
767            });
768            quote! {
769                (#(#let_self),*) => {
770                    #(#list_hashes);*
771                }
772            }
773        }
774        syn::Fields::Unit => quote! {
775            => {}
776        },
777    }
778}
779
780fn gen_list_hashes(data: &Data, attrs: &[Attribute]) -> proc_macro2::TokenStream {
781    let untagged = match parse_untagged(attrs) {
782        Ok(untagged) => untagged,
783        Err(e) => return e.into_compile_error(),
784    };
785    match data {
786        Data::Struct(data) => {
787            let arm = fields_list_hashes(&data.fields);
788            quote! {
789                match self {
790                    Self #arm
791                }
792            }
793        }
794        Data::Enum(data) => {
795            if data.variants.is_empty() {
796                return quote! {};
797            }
798            let to_output = data.variants.iter().map(|v| {
799                let ident = &v.ident;
800                let arm = fields_list_hashes(&v.fields);
801                quote! { Self::#ident #arm }
802            });
803            let tagged = if untagged.is_none() {
804                quote! {
805                    let kind = ::object_rainbow::Enum::kind(self);
806                    let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
807                    tag.list_hashes(visitor);
808                }
809            } else {
810                quote! {}
811            };
812            quote! {
813                #tagged;
814                match self {
815                    #(#to_output)*
816                }
817            }
818        }
819        Data::Union(data) => {
820            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
821        }
822    }
823}
824
825/// ```rust
826/// use object_rainbow::{ListHashes, Topological};
827///
828/// #[derive(ListHashes, Topological)]
829/// struct Three<A, B, C> {
830///     a: A,
831///     b: B,
832///     c: C,
833/// }
834///
835/// object_rainbow::assert_impl!(
836///     impl<A, B, C> Topological for Three<A, B, C>
837///     where
838///         A: Topological,
839///         B: Topological,
840///         C: Topological,
841///     {}
842/// );
843/// ```
844#[proc_macro_derive(Topological, attributes(topology))]
845pub fn derive_topological(input: TokenStream) -> TokenStream {
846    let input = parse_macro_input!(input as DeriveInput);
847    let name = input.ident;
848    let generics = input.generics.clone();
849    let (_, ty_generics, _) = generics.split_for_impl();
850    let generics = match bounds_topological(input.generics, &input.data, &input.attrs, &name) {
851        Ok(g) => g,
852        Err(e) => return e.into_compile_error().into(),
853    };
854    let traverse = gen_traverse(&input.data, &input.attrs);
855    let (impl_generics, _, where_clause) = generics.split_for_impl();
856    let target = parse_for(&name, &input.attrs);
857    let output = quote! {
858        const _: () = {
859            #[automatically_derived]
860            impl #impl_generics ::object_rainbow::Topological for #target #ty_generics
861            #where_clause
862            {
863                fn traverse(&self, visitor: &mut (impl ?::core::marker::Sized + ::object_rainbow::PointVisitor)) {
864                    #traverse
865                }
866            }
867        };
868    };
869    TokenStream::from(output)
870}
871
872#[derive(Debug, FromMeta)]
873#[darling(derive_syn_parse)]
874struct ContainerTopologyArgs {
875    #[darling(default)]
876    recursive: bool,
877    #[darling(default)]
878    inline: bool,
879    #[darling(default)]
880    unchecked: bool,
881    #[darling(default)]
882    bound: Option<LitStr>,
883}
884
885fn parse_recursive_inline(
886    attrs: &[Attribute],
887) -> syn::Result<(bool, bool, bool, Vec<WherePredicate>)> {
888    let mut r = false;
889    let mut i = false;
890    let mut u = false;
891    let mut wheres = Vec::new();
892    for attr in attrs {
893        if attr_str(attr).as_deref() == Some("topology") {
894            let ContainerTopologyArgs {
895                recursive,
896                inline,
897                unchecked,
898                bound,
899            } = attr.parse_args()?;
900            if recursive {
901                r = true;
902            }
903            if inline {
904                i = true;
905            }
906            if unchecked {
907                u = true;
908            }
909            if let Some(bound) = bound {
910                wheres.push(bound.parse()?);
911            }
912        }
913    }
914    Ok((r, i, u, wheres))
915}
916
917#[derive(Debug, FromMeta)]
918#[darling(derive_syn_parse)]
919struct FieldTopologyArgs {
920    #[darling(default)]
921    unchecked: bool,
922    with: Option<Expr>,
923}
924
925fn bounds_topological(
926    mut generics: Generics,
927    data: &Data,
928    attrs: &[Attribute],
929    name: &Ident,
930) -> syn::Result<Generics> {
931    let (recursive, inline, u, wheres) = parse_recursive_inline(attrs)?;
932    let g = &bounds_g(&generics);
933    let bound = if recursive {
934        quote! { ::object_rainbow::Traversible }
935    } else {
936        quote! { ::object_rainbow::Topological }
937    };
938    match data {
939        Data::Struct(data) => {
940            'field: for f in data.fields.iter() {
941                let ty = &f.ty;
942                for attr in &f.attrs {
943                    if attr_str(attr).as_deref() == Some("topology") {
944                        let FieldTopologyArgs { unchecked, .. } = attr.parse_args()?;
945                        if unchecked {
946                            continue 'field;
947                        }
948                    }
949                }
950                if u {
951                    continue 'field;
952                }
953                if type_contains_generics(GContext { g, always: false }, ty) {
954                    generics.make_where_clause().predicates.push(
955                        parse_quote_spanned! { ty.span() =>
956                            #ty: #bound
957                        },
958                    );
959                }
960            }
961        }
962        Data::Enum(data) => {
963            for v in data.variants.iter() {
964                'field: for f in v.fields.iter() {
965                    let ty = &f.ty;
966                    for attr in &f.attrs {
967                        if attr_str(attr).as_deref() == Some("topology") {
968                            let FieldTopologyArgs { unchecked, .. } = attr.parse_args()?;
969                            if unchecked {
970                                continue 'field;
971                            }
972                        }
973                    }
974                    if u {
975                        continue 'field;
976                    }
977                    if type_contains_generics(GContext { g, always: false }, ty) {
978                        generics.make_where_clause().predicates.push(
979                            parse_quote_spanned! { ty.span() =>
980                                #ty: #bound
981                            },
982                        );
983                    }
984                }
985            }
986        }
987        Data::Union(data) => {
988            return Err(Error::new_spanned(
989                data.union_token,
990                "`union`s are not supported",
991            ));
992        }
993    }
994    let output_bound = if inline {
995        quote! {
996            ::object_rainbow::InlineOutput
997        }
998    } else {
999        quote! {
1000            ::object_rainbow::ToOutput
1001        }
1002    };
1003    if recursive {
1004        generics
1005            .make_where_clause()
1006            .predicates
1007            .push(parse_quote_spanned! { name.span() =>
1008                Self: #output_bound + ::object_rainbow::Tagged
1009            });
1010    }
1011    for bound in wheres {
1012        generics.make_where_clause().predicates.push(bound);
1013    }
1014    Ok(generics)
1015}
1016
1017fn fields_traverse(fields: &syn::Fields) -> proc_macro2::TokenStream {
1018    match fields {
1019        syn::Fields::Named(fields) => {
1020            let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
1021            let traverse = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
1022                let mut w = None;
1023                for attr in &f.attrs {
1024                    if attr_str(attr).as_deref() == Some("topology") {
1025                        let FieldTopologyArgs { with, .. } = match attr.parse_args() {
1026                            Ok(args) => args,
1027                            Err(e) => return e.into_compile_error(),
1028                        };
1029                        if let Some(with) = with {
1030                            w = Some(with);
1031                        }
1032                    }
1033                }
1034                if let Some(with) = w {
1035                    quote_spanned! { f.ty.span() =>
1036                        #with(#i, visitor)
1037                    }
1038                } else {
1039                    quote_spanned! { f.ty.span() =>
1040                        #i.traverse(visitor)
1041                    }
1042                }
1043            });
1044            quote! {
1045                { #(#let_self),* } => {
1046                    #(#traverse);*
1047                }
1048            }
1049        }
1050        syn::Fields::Unnamed(fields) => {
1051            let let_self = fields
1052                .unnamed
1053                .iter()
1054                .enumerate()
1055                .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
1056            let traverse = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
1057                let mut w = None;
1058                for attr in &f.attrs {
1059                    if attr_str(attr).as_deref() == Some("topology") {
1060                        let FieldTopologyArgs { with, .. } = match attr.parse_args() {
1061                            Ok(args) => args,
1062                            Err(e) => return e.into_compile_error(),
1063                        };
1064                        if let Some(with) = with {
1065                            w = Some(with);
1066                        }
1067                    }
1068                }
1069                if let Some(with) = w {
1070                    quote_spanned! { f.ty.span() =>
1071                        #with(#i, visitor)
1072                    }
1073                } else {
1074                    quote_spanned! { f.ty.span() =>
1075                        #i.traverse(visitor)
1076                    }
1077                }
1078            });
1079            quote! {
1080                (#(#let_self),*) => {
1081                    #(#traverse);*
1082                }
1083            }
1084        }
1085        syn::Fields::Unit => quote! {
1086            => {}
1087        },
1088    }
1089}
1090
1091fn gen_traverse(data: &Data, attrs: &[Attribute]) -> proc_macro2::TokenStream {
1092    let untagged = match parse_untagged(attrs) {
1093        Ok(untagged) => untagged,
1094        Err(e) => return e.into_compile_error(),
1095    };
1096    match data {
1097        Data::Struct(data) => {
1098            let arm = fields_traverse(&data.fields);
1099            quote! {
1100                match self {
1101                    Self #arm
1102                }
1103            }
1104        }
1105        Data::Enum(data) => {
1106            if data.variants.is_empty() {
1107                return quote! {};
1108            }
1109            let to_output = data.variants.iter().map(|v| {
1110                let ident = &v.ident;
1111                let arm = fields_traverse(&v.fields);
1112                quote! { Self::#ident #arm }
1113            });
1114            let tagged = if untagged.is_none() {
1115                quote! {
1116                    let kind = ::object_rainbow::Enum::kind(self);
1117                    let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
1118                    tag.traverse(visitor);
1119                }
1120            } else {
1121                quote! {}
1122            };
1123            quote! {
1124                #tagged;
1125                match self {
1126                    #(#to_output)*
1127                }
1128            }
1129        }
1130        Data::Union(data) => {
1131            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1132        }
1133    }
1134}
1135
1136/// ```rust
1137/// use object_rainbow::Tagged;
1138///
1139/// #[derive(Tagged)]
1140/// struct Three<A, B, C> {
1141///     a: A,
1142///     #[tags(skip)]
1143///     b: B,
1144///     c: C,
1145/// }
1146///
1147/// object_rainbow::assert_impl!(
1148///     impl<A, B, C> Tagged for Three<A, B, C>
1149///     where
1150///         A: Tagged,
1151///         C: Tagged,
1152///     {}
1153/// );
1154/// ```
1155#[proc_macro_derive(Tagged, attributes(tags))]
1156pub fn derive_tagged(input: TokenStream) -> TokenStream {
1157    let input = parse_macro_input!(input as DeriveInput);
1158    let name = input.ident;
1159    let mut errors = Vec::new();
1160    let generics = match bounds_tagged(input.generics, &input.data, &mut errors) {
1161        Ok(g) => g,
1162        Err(e) => return e.into_compile_error().into(),
1163    };
1164    let tags = gen_tags(&input.data, &input.attrs, &mut errors);
1165    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
1166    let errors = errors.into_iter().map(|e| e.into_compile_error());
1167    let target = parse_for(&name, &input.attrs);
1168    let output = quote! {
1169        #(#errors)*
1170
1171        #[automatically_derived]
1172        impl #impl_generics ::object_rainbow::Tagged for #target #ty_generics #where_clause {
1173            const TAGS: ::object_rainbow::Tags = #tags;
1174        }
1175    };
1176    TokenStream::from(output)
1177}
1178
1179#[derive(Debug, FromMeta)]
1180#[darling(derive_syn_parse)]
1181struct FieldTagArgs {
1182    #[darling(default)]
1183    skip: bool,
1184    replace: Option<Type>,
1185}
1186
1187fn bounds_tagged(
1188    mut generics: Generics,
1189    data: &Data,
1190    errors: &mut Vec<Error>,
1191) -> syn::Result<Generics> {
1192    let g = &bounds_g(&generics);
1193    match data {
1194        Data::Struct(data) => {
1195            for f in data.fields.iter() {
1196                let mut skip = false;
1197                let mut replace = Vec::new();
1198                for attr in &f.attrs {
1199                    if attr_str(attr).as_deref() == Some("tags") {
1200                        match attr.parse_args::<FieldTagArgs>() {
1201                            Ok(args) => {
1202                                skip |= args.skip;
1203                                replace.extend(args.replace);
1204                            }
1205                            Err(e) => {
1206                                errors.push(e);
1207                            }
1208                        }
1209                    }
1210                }
1211                if !replace.is_empty() {
1212                    for replace in replace {
1213                        generics.make_where_clause().predicates.push(
1214                            parse_quote_spanned! { replace.span() =>
1215                                #replace: ::object_rainbow::Tagged
1216                            },
1217                        );
1218                    }
1219                } else if !skip {
1220                    let ty = &f.ty;
1221                    if type_contains_generics(GContext { g, always: false }, ty) {
1222                        generics.make_where_clause().predicates.push(
1223                            parse_quote_spanned! { ty.span() =>
1224                                #ty: ::object_rainbow::Tagged
1225                            },
1226                        );
1227                    }
1228                }
1229            }
1230        }
1231        Data::Enum(data) => {
1232            for v in data.variants.iter() {
1233                for f in v.fields.iter() {
1234                    let mut skip = false;
1235                    let mut replace = Vec::new();
1236                    for attr in &f.attrs {
1237                        if attr_str(attr).as_deref() == Some("tags") {
1238                            match attr.parse_args::<FieldTagArgs>() {
1239                                Ok(args) => {
1240                                    skip |= args.skip;
1241                                    replace.extend(args.replace);
1242                                }
1243                                Err(e) => {
1244                                    errors.push(e);
1245                                }
1246                            }
1247                        }
1248                    }
1249                    if !replace.is_empty() {
1250                        for replace in replace {
1251                            generics.make_where_clause().predicates.push(
1252                                parse_quote_spanned! { replace.span() =>
1253                                    #replace: ::object_rainbow::Tagged
1254                                },
1255                            );
1256                        }
1257                    } else if !skip {
1258                        let ty = &f.ty;
1259                        if type_contains_generics(GContext { g, always: false }, ty) {
1260                            generics.make_where_clause().predicates.push(
1261                                parse_quote_spanned! { ty.span() =>
1262                                    #ty: ::object_rainbow::Tagged
1263                                },
1264                            );
1265                        }
1266                    }
1267                }
1268            }
1269        }
1270        Data::Union(data) => {
1271            return Err(Error::new_spanned(
1272                data.union_token,
1273                "`union`s are not supported",
1274            ));
1275        }
1276    }
1277    Ok(generics)
1278}
1279
1280struct StructTagArgs {
1281    tags: Vec<LitStr>,
1282}
1283
1284impl Parse for StructTagArgs {
1285    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
1286        let mut tags = Vec::new();
1287        while !input.is_empty() {
1288            let tag = input.parse::<LitStr>()?;
1289            tags.push(tag);
1290            if !input.is_empty() {
1291                input.parse::<Comma>()?;
1292            }
1293        }
1294        Ok(Self { tags })
1295    }
1296}
1297
1298fn fields_tags(fields: &syn::Fields) -> Vec<proc_macro2::TokenStream> {
1299    fields
1300        .iter()
1301        .filter_map(|f| {
1302            let mut skip = false;
1303            let mut replace = None;
1304            for attr in &f.attrs {
1305                if attr_str(attr).as_deref() == Some("tags") {
1306                    let args = attr.parse_args::<FieldTagArgs>().ok()?;
1307                    skip |= args.skip;
1308                    replace = replace.or(args.replace);
1309                }
1310            }
1311            let ty = &f.ty;
1312            if let Some(replace) = replace {
1313                Some(quote! { <#replace as ::object_rainbow::Tagged>::TAGS })
1314            } else if !skip {
1315                Some(quote! { <#ty as ::object_rainbow::Tagged>::TAGS })
1316            } else {
1317                None
1318            }
1319        })
1320        .collect()
1321}
1322
1323fn gen_tags(data: &Data, attrs: &[Attribute], errors: &mut Vec<Error>) -> proc_macro2::TokenStream {
1324    let untagged = match parse_untagged(attrs) {
1325        Ok(untagged) => untagged,
1326        Err(e) => return e.into_compile_error(),
1327    };
1328    match data {
1329        Data::Struct(data) => {
1330            let mut tags = Vec::new();
1331            for attr in attrs {
1332                if attr_str(attr).as_deref() == Some("tags") {
1333                    match attr.parse_args::<StructTagArgs>() {
1334                        Ok(mut args) => tags.append(&mut args.tags),
1335                        Err(e) => errors.push(e),
1336                    }
1337                }
1338            }
1339            let nested = fields_tags(&data.fields);
1340            if nested.len() == 1 && tags.is_empty() {
1341                let nested = nested.into_iter().next().unwrap();
1342                quote! {
1343                    #nested
1344                }
1345            } else {
1346                quote! {
1347                    ::object_rainbow::Tags(&[#(#tags),*], &[#(&#nested),*])
1348                }
1349            }
1350        }
1351        Data::Enum(data) => {
1352            let mut tags = Vec::new();
1353            for attr in attrs {
1354                if attr_str(attr).as_deref() == Some("tags") {
1355                    match attr.parse_args::<StructTagArgs>() {
1356                        Ok(mut args) => tags.append(&mut args.tags),
1357                        Err(e) => errors.push(e),
1358                    }
1359                }
1360            }
1361            let mut nested: Vec<_> = data
1362                .variants
1363                .iter()
1364                .flat_map(|v| fields_tags(&v.fields))
1365                .collect();
1366            let kind_tags = quote! {
1367                <
1368                    <
1369                        <
1370                            Self
1371                            as
1372                            ::object_rainbow::Enum
1373                        >::Kind
1374                        as
1375                        ::object_rainbow::enumkind::EnumKind
1376                    >::Tag
1377                    as  ::object_rainbow::Tagged
1378                >::TAGS
1379            };
1380            if untagged.is_none() {
1381                nested.insert(0, kind_tags);
1382            }
1383            if nested.len() == 1 && tags.is_empty() {
1384                let nested = nested.into_iter().next().unwrap();
1385                quote! {
1386                    #nested
1387                }
1388            } else {
1389                quote! {
1390                    ::object_rainbow::Tags(&[#(#tags),*], &[#(&#nested),*])
1391                }
1392            }
1393        }
1394        Data::Union(data) => {
1395            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1396        }
1397    }
1398}
1399
1400/// ```rust
1401/// use object_rainbow::Size;
1402///
1403/// #[derive(Size)]
1404/// struct Three<A, B, C> {
1405///     a: A,
1406///     b: B,
1407///     c: C,
1408/// }
1409///
1410/// object_rainbow::assert_impl!(
1411///     impl<A, B, C> Size for Three<A, B, C>
1412///     where
1413///         A: Size<Size = typenum::U2>,
1414///         B: Size<Size = typenum::U3>,
1415///         C: Size<Size = typenum::U7>,
1416///     {}
1417/// );
1418///
1419/// assert_eq!(Three::<[u8; 2], [u8; 3], [u8; 7]>::SIZE, 12);
1420/// ```
1421#[proc_macro_derive(Size)]
1422pub fn derive_size(input: TokenStream) -> TokenStream {
1423    let input = parse_macro_input!(input as DeriveInput);
1424    let name = input.ident;
1425    let size_arr = gen_size_arr(&input.data);
1426    let size = gen_size(&input.data);
1427    let mut original_generics = input.generics.clone();
1428    let (generics, needs_output) = match bounds_size(input.generics.clone(), &input.data, &size_arr)
1429    {
1430        Ok(g) => g,
1431        Err(e) => return e.into_compile_error().into(),
1432    };
1433    let generics_array = generics.clone();
1434    let (_, _, where_clause_array) = generics_array.split_for_impl();
1435    original_generics
1436        .make_where_clause()
1437        .predicates
1438        .push(parse_quote!(
1439            Self: ::object_rainbow::SizeSumHelper<
1440                SizeArray: ::object_rainbow::typenum::FoldAdd<
1441                    Output: ::object_rainbow::typenum::Unsigned
1442                >
1443            >
1444        ));
1445    let (impl_generics, ty_generics, where_clause) = original_generics.split_for_impl();
1446    let mut generics = input.generics;
1447    if needs_output {
1448        generics.params.push(parse_quote!(
1449            __Output: ::object_rainbow::typenum::Unsigned
1450        ));
1451    }
1452    let (impl_generics_array, _, _) = generics.split_for_impl();
1453    let target = parse_for(&name, &input.attrs);
1454    let output = quote! {
1455        const _: () = {
1456            use ::object_rainbow::typenum::tarr;
1457
1458            #[automatically_derived]
1459            impl #impl_generics_array ::object_rainbow::SizeSumHelper
1460            for #target #ty_generics #where_clause_array {
1461                const SIZE_ARRAY: usize = #size;
1462                type SizeArray = #size_arr;
1463            }
1464
1465            #[automatically_derived]
1466            impl #impl_generics ::object_rainbow::Size for #target #ty_generics #where_clause {
1467                const SIZE: usize = <Self as ::object_rainbow::SizeSumHelper>::SIZE_ARRAY;
1468                type Size = <
1469                    <Self as ::object_rainbow::SizeSumHelper>::SizeArray
1470                    as
1471                    ::object_rainbow::typenum::FoldAdd
1472                >::Output;
1473            }
1474        };
1475    };
1476    TokenStream::from(output)
1477}
1478
1479fn bounds_size(
1480    mut generics: Generics,
1481    data: &Data,
1482    size_arr: &proc_macro2::TokenStream,
1483) -> syn::Result<(Generics, bool)> {
1484    let g = &bounds_g(&generics);
1485    let is_enum = match data {
1486        Data::Struct(data) => {
1487            for f in data.fields.iter() {
1488                let ty = &f.ty;
1489                if type_contains_generics(GContext { g, always: false }, ty) {
1490                    generics.make_where_clause().predicates.push(
1491                        parse_quote_spanned! { ty.span() =>
1492                            #ty: ::object_rainbow::Size
1493                        },
1494                    );
1495                }
1496            }
1497            if generics.params.is_empty() {
1498                generics.make_where_clause().predicates.push(parse_quote!(
1499                    #size_arr: ::object_rainbow::typenum::FoldAdd<
1500                        Output: ::object_rainbow::typenum::Unsigned
1501                    >
1502                ));
1503                false
1504            } else {
1505                generics.make_where_clause().predicates.push(parse_quote!(
1506                    #size_arr: ::object_rainbow::typenum::FoldAdd<
1507                        Output = __Output
1508                    >
1509                ));
1510                true
1511            }
1512        }
1513        Data::Enum(data) => {
1514            for v in data.variants.iter() {
1515                for f in v.fields.iter() {
1516                    let ty = &f.ty;
1517                    if type_contains_generics(GContext { g, always: false }, ty) {
1518                        generics.make_where_clause().predicates.push(
1519                            parse_quote_spanned! { ty.span() =>
1520                                #ty: ::object_rainbow::Size
1521                            },
1522                        );
1523                    }
1524                }
1525            }
1526            for v in data.variants.iter().skip(1) {
1527                let arr = fields_size_arr(&v.fields, true);
1528                generics.make_where_clause().predicates.push(parse_quote!(
1529                    #arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
1530                ));
1531            }
1532            generics.make_where_clause().predicates.push(parse_quote!(
1533                #size_arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
1534            ));
1535            true
1536        }
1537        Data::Union(data) => {
1538            return Err(Error::new_spanned(
1539                data.union_token,
1540                "`union`s are not supported",
1541            ));
1542        }
1543    };
1544    Ok((generics, is_enum))
1545}
1546
1547fn fields_size_arr(fields: &syn::Fields, as_enum: bool) -> proc_macro2::TokenStream {
1548    let kind_size = quote! {
1549        <
1550            <
1551                <
1552                    Self
1553                    as
1554                    ::object_rainbow::Enum
1555                >::Kind
1556                as
1557                ::object_rainbow::enumkind::EnumKind
1558            >::Tag
1559            as  ::object_rainbow::Size
1560        >::Size
1561    };
1562    if fields.is_empty() {
1563        return if as_enum {
1564            quote! { tarr![#kind_size, ::object_rainbow::typenum::consts::U0] }
1565        } else {
1566            quote! { tarr![::object_rainbow::typenum::consts::U0] }
1567        };
1568    }
1569    let size_arr = fields.iter().map(|f| {
1570        let ty = &f.ty;
1571        quote! { <#ty as ::object_rainbow::Size>::Size }
1572    });
1573    if as_enum {
1574        quote! { tarr![#kind_size, ::object_rainbow::typenum::consts::U0, #(#size_arr),*] }
1575    } else {
1576        quote! { tarr![::object_rainbow::typenum::consts::U0, #(#size_arr),*] }
1577    }
1578}
1579
1580fn gen_size_arr(data: &Data) -> proc_macro2::TokenStream {
1581    match data {
1582        Data::Struct(data) => fields_size_arr(&data.fields, false),
1583        Data::Enum(data) => {
1584            if let Some(v) = data.variants.first() {
1585                fields_size_arr(&v.fields, true)
1586            } else {
1587                Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
1588                    .into_compile_error()
1589            }
1590        }
1591        Data::Union(data) => {
1592            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1593        }
1594    }
1595}
1596
1597fn fields_size(fields: &syn::Fields) -> proc_macro2::TokenStream {
1598    if fields.is_empty() {
1599        return quote! {0};
1600    }
1601    let size = fields.iter().map(|f| {
1602        let ty = &f.ty;
1603        quote! { <#ty as ::object_rainbow::Size>::SIZE }
1604    });
1605    quote! {
1606        #(#size)+*
1607    }
1608}
1609
1610fn gen_size(data: &Data) -> proc_macro2::TokenStream {
1611    match data {
1612        Data::Struct(data) => fields_size(&data.fields),
1613        Data::Enum(data) => {
1614            if let Some(v) = data.variants.first() {
1615                let size = fields_size(&v.fields);
1616                let kind_size = quote! {
1617                    <
1618                        <
1619                            <
1620                                Self
1621                                as
1622                                ::object_rainbow::Enum
1623                            >::Kind
1624                            as
1625                            ::object_rainbow::enumkind::EnumKind
1626                        >::Tag
1627                        as  ::object_rainbow::Size
1628                    >::SIZE
1629                };
1630                quote! { #kind_size + #size }
1631            } else {
1632                Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
1633                    .into_compile_error()
1634            }
1635        }
1636        Data::Union(data) => {
1637            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1638        }
1639    }
1640}
1641
1642/// ```rust
1643/// use object_rainbow::{Parse, ParseInline, ParseInput};
1644///
1645/// #[derive(Parse)]
1646/// struct Three<A, B, C> {
1647///     a: A,
1648///     b: B,
1649///     c: C,
1650/// }
1651///
1652/// object_rainbow::assert_impl!(
1653///     impl<A, B, C, I> Parse<I> for Three<A, B, C>
1654///     where
1655///         A: ParseInline<I>,
1656///         B: ParseInline<I>,
1657///         C: Parse<I>,
1658///         I: ParseInput,
1659///     {}
1660/// );
1661/// ```
1662#[proc_macro_derive(Parse, attributes(parse))]
1663pub fn derive_parse(input: TokenStream) -> TokenStream {
1664    let input = parse_macro_input!(input as DeriveInput);
1665    let name = input.ident;
1666    let generics = input.generics.clone();
1667    let (_, ty_generics, _) = generics.split_for_impl();
1668    let (inp, generics) = match bounds_parse(input.generics, &input.data, &input.attrs) {
1669        Ok(g) => g,
1670        Err(e) => return e.into_compile_error().into(),
1671    };
1672    let (parse, enum_parse) = gen_parse(&input.data, &input.attrs);
1673    let (impl_generics, _, where_clause) = generics.split_for_impl();
1674    let target = parse_for(&name, &input.attrs);
1675    let enum_parse = enum_parse.map(|enum_parse| {
1676        quote! {
1677            #[automatically_derived]
1678            impl #impl_generics ::object_rainbow::enumkind::EnumParse<#inp> for #target #ty_generics
1679            #where_clause
1680            {
1681                fn enum_parse(
1682                    kind: <Self as ::object_rainbow::Enum>::Kind, mut input: #inp,
1683                ) -> ::object_rainbow::Result<Self> {
1684                    #enum_parse
1685                }
1686            }
1687        }
1688    });
1689    let output = quote! {
1690        const _: () = {
1691            #[automatically_derived]
1692            impl #impl_generics ::object_rainbow::Parse<#inp> for #target #ty_generics
1693            #where_clause
1694            {
1695                fn parse(mut input: #inp) -> ::object_rainbow::Result<Self> {
1696                    #parse
1697                }
1698            }
1699
1700            #enum_parse
1701        };
1702    };
1703    TokenStream::from(output)
1704}
1705
1706#[derive(Debug, FromMeta)]
1707#[darling(derive_syn_parse)]
1708struct ContainerParseArgs {
1709    #[darling(default)]
1710    unchecked: bool,
1711    #[darling(default)]
1712    bound: Option<LitStr>,
1713    #[darling(default)]
1714    generic: Option<LitStr>,
1715    #[darling(default)]
1716    input: Option<LitStr>,
1717}
1718
1719fn parse_parse_args(
1720    attrs: &[Attribute],
1721) -> syn::Result<(bool, Ident, Vec<WherePredicate>, Vec<GenericParam>)> {
1722    let mut u = false;
1723    let mut inp = parse_quote!(__I);
1724    let mut wheres = Vec::new();
1725    let mut ig = Vec::new();
1726    for attr in attrs {
1727        if attr_str(attr).as_deref() == Some("parse") {
1728            let ContainerParseArgs {
1729                unchecked,
1730                input,
1731                bound,
1732                generic,
1733            } = attr.parse_args()?;
1734            if unchecked {
1735                u = true;
1736            }
1737            if let Some(input) = input {
1738                inp = input.parse()?;
1739            }
1740            if let Some(bound) = bound {
1741                wheres.push(bound.parse()?);
1742            }
1743            if let Some(generic) = generic {
1744                ig.push(generic.parse()?);
1745            }
1746        }
1747    }
1748    Ok((u, inp, wheres, ig))
1749}
1750
1751#[derive(Debug, FromMeta)]
1752#[darling(derive_syn_parse)]
1753struct ParseArgs {
1754    #[darling(default)]
1755    unchecked: bool,
1756    with: Option<Expr>,
1757}
1758
1759fn bounds_parse(
1760    mut generics: Generics,
1761    data: &Data,
1762    attrs: &[Attribute],
1763) -> syn::Result<(Ident, Generics)> {
1764    let (recursive, _, _, _) = parse_recursive_inline(attrs)?;
1765    let (u, inp, wheres, ig) = parse_parse_args(attrs)?;
1766    let tr = |last| match (last, recursive) {
1767        (true, true) => {
1768            quote!(::object_rainbow::Parse<#inp> + ::object_rainbow::Object<#inp::Extra>)
1769        }
1770        (true, false) => quote!(::object_rainbow::Parse<#inp>),
1771        (false, true) => {
1772            quote!(::object_rainbow::ParseInline<#inp> + ::object_rainbow::Inline<#inp::Extra>)
1773        }
1774        (false, false) => quote!(::object_rainbow::ParseInline<#inp>),
1775    };
1776    match data {
1777        Data::Struct(data) => {
1778            let last_at = data.fields.len().saturating_sub(1);
1779            'field: for (i, f) in data.fields.iter().enumerate() {
1780                let last = i == last_at;
1781                let ty = &f.ty;
1782                for attr in &f.attrs {
1783                    if attr_str(attr).as_deref() == Some("parse") {
1784                        let ParseArgs { unchecked, .. } = attr.parse_args::<ParseArgs>()?;
1785                        if unchecked {
1786                            continue 'field;
1787                        }
1788                    }
1789                }
1790                if u {
1791                    continue 'field;
1792                }
1793                let tr = tr(last);
1794                generics
1795                    .make_where_clause()
1796                    .predicates
1797                    .push(parse_quote_spanned! { ty.span() =>
1798                        #ty: #tr
1799                    });
1800            }
1801        }
1802        Data::Enum(data) => {
1803            for v in data.variants.iter() {
1804                let last_at = v.fields.len().saturating_sub(1);
1805                'field: for (i, f) in v.fields.iter().enumerate() {
1806                    let ty = &f.ty;
1807                    for attr in &f.attrs {
1808                        if attr_str(attr).as_deref() == Some("parse") {
1809                            let ParseArgs { unchecked, .. } = attr.parse_args::<ParseArgs>()?;
1810                            if unchecked {
1811                                continue 'field;
1812                            }
1813                        }
1814                    }
1815                    if u {
1816                        continue 'field;
1817                    }
1818                    let last = i == last_at;
1819                    let tr = tr(last);
1820                    generics.make_where_clause().predicates.push(
1821                        parse_quote_spanned! { ty.span() =>
1822                            #ty: #tr
1823                        },
1824                    );
1825                }
1826            }
1827        }
1828        Data::Union(data) => {
1829            return Err(Error::new_spanned(
1830                data.union_token,
1831                "`union`s are not supported",
1832            ));
1833        }
1834    }
1835    generics.params.push(if recursive {
1836        parse_quote!(#inp: ::object_rainbow::PointInput<
1837            Extra: ::core::marker::Send + ::core::marker::Sync + ::core::clone::Clone
1838        >)
1839    } else {
1840        parse_quote!(#inp: ::object_rainbow::ParseInput)
1841    });
1842    for bound in wheres {
1843        generics.make_where_clause().predicates.push(bound);
1844    }
1845    generics.params.extend(ig);
1846    Ok((inp, generics))
1847}
1848
1849fn gen_parse(
1850    data: &Data,
1851    attrs: &[Attribute],
1852) -> (proc_macro2::TokenStream, Option<proc_macro2::TokenStream>) {
1853    match parse_untagged(attrs) {
1854        Ok(None) => {}
1855        Ok(Some(untagged)) => {
1856            return (
1857                syn::Error::new(untagged.span(), "`untagged` cannot be parsed")
1858                    .into_compile_error(),
1859                None,
1860            );
1861        }
1862        Err(e) => return (e.into_compile_error(), None),
1863    };
1864    match data {
1865        Data::Struct(data) => {
1866            let arm = fields_parse(&data.fields);
1867            (quote! { Ok(Self #arm)}, None)
1868        }
1869        Data::Enum(data) => {
1870            let parse = data.variants.iter().map(|v| {
1871                let ident = &v.ident;
1872                let arm = fields_parse(&v.fields);
1873                quote! {
1874                    <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
1875                }
1876            });
1877            (
1878                quote! {
1879                    ::object_rainbow::enumkind::EnumParse::parse_as_enum(input)
1880                },
1881                Some(if data.variants.is_empty() {
1882                    quote! {
1883                        match kind {}
1884                    }
1885                } else {
1886                    quote! {
1887                        Ok(match kind {
1888                            #(#parse)*
1889                        })
1890                    }
1891                }),
1892            )
1893        }
1894        Data::Union(data) => (
1895            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error(),
1896            None,
1897        ),
1898    }
1899}
1900
1901fn fields_parse(fields: &syn::Fields) -> proc_macro2::TokenStream {
1902    let last_at = fields.len().saturating_sub(1);
1903    match fields {
1904        syn::Fields::Named(fields) => {
1905            let parse = fields.named.iter().enumerate().map(|(i, f)| {
1906                let last = i == last_at;
1907                let mut w = None;
1908                for attr in &f.attrs {
1909                    if attr_str(attr).as_deref() == Some("parse") {
1910                        let ParseArgs { with, .. } = match attr.parse_args::<ParseArgs>() {
1911                            Ok(args) => args,
1912                            Err(e) => return e.into_compile_error(),
1913                        };
1914                        if let Some(with) = with {
1915                            w = Some(with);
1916                        }
1917                    }
1918                }
1919                let i = f.ident.as_ref().unwrap();
1920                if let Some(with) = w {
1921                    let arg = if last {
1922                        quote!(input)
1923                    } else {
1924                        quote!(&mut input)
1925                    };
1926                    quote_spanned! { f.ty.span() =>
1927                        #i: #with(#arg)?
1928                    }
1929                } else {
1930                    let method = if last {
1931                        quote!(parse)
1932                    } else {
1933                        quote!(parse_inline)
1934                    };
1935                    quote_spanned! { f.ty.span() =>
1936                        #i: input.#method()?
1937                    }
1938                }
1939            });
1940            quote! { { #(#parse),* } }
1941        }
1942        syn::Fields::Unnamed(fields) => {
1943            let parse = fields.unnamed.iter().enumerate().map(|(i, f)| {
1944                let mut w = None;
1945                for attr in &f.attrs {
1946                    if attr_str(attr).as_deref() == Some("parse") {
1947                        let ParseArgs { with, .. } = match attr.parse_args::<ParseArgs>() {
1948                            Ok(args) => args,
1949                            Err(e) => return e.into_compile_error(),
1950                        };
1951                        if let Some(with) = with {
1952                            w = Some(with);
1953                        }
1954                    }
1955                }
1956                let last = i == last_at;
1957                if let Some(with) = w {
1958                    let arg = if last {
1959                        quote!(input)
1960                    } else {
1961                        quote!(&mut input)
1962                    };
1963                    quote_spanned! { f.ty.span() =>
1964                        #with(#arg)?
1965                    }
1966                } else {
1967                    let method = if last {
1968                        quote!(parse)
1969                    } else {
1970                        quote!(parse_inline)
1971                    };
1972                    quote_spanned! { f.ty.span() =>
1973                        input.#method()?
1974                    }
1975                }
1976            });
1977            quote! { (#(#parse),*) }
1978        }
1979        syn::Fields::Unit => quote! {},
1980    }
1981}
1982
1983/// ```rust
1984/// use object_rainbow::{Parse, ParseInline, ParseInput};
1985///
1986/// #[derive(Parse, ParseInline)]
1987/// struct Three<A, B, C> {
1988///     a: A,
1989///     b: B,
1990///     c: C,
1991/// }
1992///
1993/// object_rainbow::assert_impl!(
1994///     impl<A, B, C, I> ParseInline<I> for Three<A, B, C>
1995///     where
1996///         A: ParseInline<I>,
1997///         B: ParseInline<I>,
1998///         C: ParseInline<I>,
1999///         I: ParseInput,
2000///     {}
2001/// );
2002/// ```
2003#[proc_macro_derive(ParseInline, attributes(parse))]
2004pub fn derive_parse_inline(input: TokenStream) -> TokenStream {
2005    let input = parse_macro_input!(input as DeriveInput);
2006    let name = input.ident;
2007    let generics = input.generics.clone();
2008    let (_, ty_generics, _) = generics.split_for_impl();
2009    let (inp, generics) = match bounds_parse_inline(input.generics, &input.data, &input.attrs) {
2010        Ok(g) => g,
2011        Err(e) => return e.into_compile_error().into(),
2012    };
2013    let (parse_inline, enum_parse_inline) = gen_parse_inline(&input.data);
2014    let (impl_generics, _, where_clause) = generics.split_for_impl();
2015    let target = parse_for(&name, &input.attrs);
2016    let enum_parse_inline = enum_parse_inline.map(|enum_parse_inline| {
2017        quote! {
2018            #[automatically_derived]
2019            impl #impl_generics ::object_rainbow::enumkind::EnumParseInline<#inp>
2020            for #target #ty_generics #where_clause {
2021                fn enum_parse_inline(
2022                    kind: <Self as ::object_rainbow::Enum>::Kind, input: &mut #inp,
2023                ) -> ::object_rainbow::Result<Self> {
2024                    #enum_parse_inline
2025                }
2026            }
2027        }
2028    });
2029    let output = quote! {
2030        #[automatically_derived]
2031        impl #impl_generics ::object_rainbow::ParseInline<#inp>
2032        for #target #ty_generics #where_clause {
2033            fn parse_inline(input: &mut #inp) -> ::object_rainbow::Result<Self> {
2034                #parse_inline
2035            }
2036        }
2037
2038        #enum_parse_inline
2039    };
2040    TokenStream::from(output)
2041}
2042
2043fn bounds_parse_inline(
2044    mut generics: Generics,
2045    data: &Data,
2046    attrs: &[Attribute],
2047) -> syn::Result<(Ident, Generics)> {
2048    let (recursive, _, _, _) = parse_recursive_inline(attrs)?;
2049    let (u, inp, wheres, ig) = parse_parse_args(attrs)?;
2050    let tr = if recursive {
2051        quote!(::object_rainbow::ParseInline<#inp> + ::object_rainbow::Inline<#inp::Extra>)
2052    } else {
2053        quote!(::object_rainbow::ParseInline<#inp>)
2054    };
2055    match data {
2056        Data::Struct(data) => {
2057            'field: for f in data.fields.iter() {
2058                let ty = &f.ty;
2059                for attr in &f.attrs {
2060                    if attr_str(attr).as_deref() == Some("parse") {
2061                        let ParseArgs { unchecked, .. } = attr.parse_args::<ParseArgs>()?;
2062                        if unchecked {
2063                            continue 'field;
2064                        }
2065                    }
2066                }
2067                if u {
2068                    continue 'field;
2069                }
2070                generics
2071                    .make_where_clause()
2072                    .predicates
2073                    .push(parse_quote_spanned! { ty.span() =>
2074                        #ty: #tr
2075                    });
2076            }
2077        }
2078        Data::Enum(data) => {
2079            for v in data.variants.iter() {
2080                'field: for f in v.fields.iter() {
2081                    let ty = &f.ty;
2082                    for attr in &f.attrs {
2083                        if attr_str(attr).as_deref() == Some("parse") {
2084                            let ParseArgs { unchecked, .. } = attr.parse_args::<ParseArgs>()?;
2085                            if unchecked {
2086                                continue 'field;
2087                            }
2088                        }
2089                    }
2090                    if u {
2091                        continue 'field;
2092                    }
2093                    generics.make_where_clause().predicates.push(
2094                        parse_quote_spanned! { ty.span() =>
2095                            #ty: #tr
2096                        },
2097                    );
2098                }
2099            }
2100        }
2101        Data::Union(data) => {
2102            return Err(Error::new_spanned(
2103                data.union_token,
2104                "`union`s are not supported",
2105            ));
2106        }
2107    }
2108    generics.params.push(if recursive {
2109        parse_quote!(#inp: ::object_rainbow::PointInput<
2110            Extra: ::core::marker::Send + ::core::marker::Sync
2111        >)
2112    } else {
2113        parse_quote!(#inp: ::object_rainbow::ParseInput)
2114    });
2115    for bound in wheres {
2116        generics.make_where_clause().predicates.push(bound);
2117    }
2118    for generic in ig {
2119        generics.params.push(parse_quote!(#generic));
2120    }
2121    Ok((inp, generics))
2122}
2123
2124fn fields_parse_inline(fields: &syn::Fields) -> proc_macro2::TokenStream {
2125    match fields {
2126        syn::Fields::Named(fields) => {
2127            let parse = fields.named.iter().map(|f| {
2128                let i = f.ident.as_ref().unwrap();
2129                quote_spanned! { f.ty.span() =>
2130                    #i: input.parse_inline()?
2131                }
2132            });
2133            quote! { { #(#parse),* } }
2134        }
2135        syn::Fields::Unnamed(fields) => {
2136            let parse = fields.unnamed.iter().map(|f| {
2137                quote_spanned! { f.ty.span() =>
2138                    input.parse_inline()?
2139                }
2140            });
2141            quote! { (#(#parse),*) }
2142        }
2143        syn::Fields::Unit => quote! {},
2144    }
2145}
2146
2147fn gen_parse_inline(data: &Data) -> (proc_macro2::TokenStream, Option<proc_macro2::TokenStream>) {
2148    match data {
2149        Data::Struct(data) => {
2150            let arm = fields_parse_inline(&data.fields);
2151            (quote! { Ok(Self #arm) }, None)
2152        }
2153        Data::Enum(data) => {
2154            let parse_inline = data.variants.iter().map(|v| {
2155                let ident = &v.ident;
2156                let arm = fields_parse_inline(&v.fields);
2157                quote! {
2158                    <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
2159                }
2160            });
2161            (
2162                quote! {
2163                    ::object_rainbow::enumkind::EnumParseInline::parse_as_inline_enum(input)
2164                },
2165                Some(if data.variants.is_empty() {
2166                    quote! {
2167                        match kind {}
2168                    }
2169                } else {
2170                    quote! {
2171                        Ok(match kind {
2172                            #(#parse_inline)*
2173                        })
2174                    }
2175                }),
2176            )
2177        }
2178        Data::Union(data) => (
2179            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error(),
2180            None,
2181        ),
2182    }
2183}
2184
2185/// ```rust
2186/// use object_rainbow::{Parse, ParseAsInline, ParseInline, ParseInput};
2187///
2188/// #[derive(ParseAsInline)]
2189/// struct Thing<T> {
2190///     inner: T,
2191/// }
2192///
2193/// object_rainbow::assert_impl!(
2194///     impl<T, I> Parse<I> for Thing<T>
2195///     where
2196///         Thing<T>: ParseInline<I>,
2197///         I: ParseInput,
2198///     {}
2199/// );
2200/// ```
2201#[proc_macro_derive(ParseAsInline)]
2202pub fn derive_parse_as_inline(input: TokenStream) -> TokenStream {
2203    let input = parse_macro_input!(input as DeriveInput);
2204    let name = input.ident;
2205    let generics = input.generics.clone();
2206    let (_, ty_generics, _) = generics.split_for_impl();
2207    let generics = match bounds_parse_as_inline(input.generics, &name) {
2208        Ok(g) => g,
2209        Err(e) => return e.into_compile_error().into(),
2210    };
2211    let (impl_generics, _, where_clause) = generics.split_for_impl();
2212    let target = parse_for(&name, &input.attrs);
2213    let output = quote! {
2214        #[automatically_derived]
2215        impl #impl_generics ::object_rainbow::Parse<__I> for #target #ty_generics #where_clause {
2216            fn parse(input: __I) -> ::object_rainbow::Result<Self> {
2217                ::object_rainbow::ParseInline::<__I>::parse_as_inline(input)
2218            }
2219        }
2220    };
2221    TokenStream::from(output)
2222}
2223
2224fn bounds_parse_as_inline(mut generics: Generics, name: &Ident) -> syn::Result<Generics> {
2225    generics
2226        .make_where_clause()
2227        .predicates
2228        .push(parse_quote_spanned! { name.span() =>
2229            Self: ::object_rainbow::ParseInline::<__I>
2230        });
2231    generics
2232        .params
2233        .push(parse_quote!(__I: ::object_rainbow::ParseInput));
2234    Ok(generics)
2235}
2236
2237fn parse_path(attr: &Attribute) -> syn::Result<Type> {
2238    attr.parse_args::<LitStr>()?.parse()
2239}
2240
2241fn attr_str(attr: &Attribute) -> Option<String> {
2242    Some(attr.path().get_ident()?.to_string())
2243}
2244
2245/// ```rust
2246/// use std::num::NonZero;
2247///
2248/// use object_rainbow::{Enum, MaybeHasNiche, ToOutput};
2249///
2250/// #[derive(Enum, ToOutput, MaybeHasNiche)]
2251/// enum WithDefault {
2252///     A(u8),
2253///     B(bool),
2254/// }
2255///
2256/// assert_eq!(Some(WithDefault::A(32)).vec(), [0, 32]);
2257/// assert_eq!(Some(WithDefault::B(true)).vec(), [1, 1]);
2258/// assert_eq!(None::<WithDefault>.vec(), [2, 0]);
2259///
2260/// #[derive(Enum, ToOutput, MaybeHasNiche)]
2261/// #[enumtag("NonZero<u8>")]
2262/// enum WithNz {
2263///     A(u8),
2264///     B(bool),
2265/// }
2266///
2267/// assert_eq!(None::<WithNz>.vec(), [0, 0]);
2268/// assert_eq!(Some(WithNz::A(32)).vec(), [1, 32]);
2269/// assert_eq!(Some(WithNz::B(true)).vec(), [2, 1]);
2270///
2271/// #[derive(Enum, ToOutput, MaybeHasNiche)]
2272/// #[enumtag("bool")]
2273/// enum WithBool {
2274///     A(u8),
2275///     B(bool),
2276/// }
2277///
2278/// assert_eq!(Some(WithBool::A(32)).vec(), [0, 32]);
2279/// assert_eq!(Some(WithBool::B(true)).vec(), [1, 1]);
2280/// assert_eq!(None::<WithBool>.vec(), [2, 0]);
2281///
2282/// #[derive(Enum, ToOutput, MaybeHasNiche)]
2283/// #[enumtag("u8")]
2284/// enum WithU8 {
2285///     A(u8),
2286///     B(bool),
2287/// }
2288///
2289/// assert_eq!(Some(WithU8::A(32)).vec(), [0, 32]);
2290/// assert_eq!(Some(WithU8::B(true)).vec(), [1, 1]);
2291/// assert_eq!(None::<WithU8>.vec(), [1, 2]);
2292///
2293/// #[derive(Enum, ToOutput, MaybeHasNiche)]
2294/// #[enumtag("u8")]
2295/// enum WithoutNiche {
2296///     A(u8),
2297///     B(u8),
2298/// }
2299///
2300/// assert_eq!(Some(WithoutNiche::A(32)).vec(), [0, 0, 32]);
2301/// assert_eq!(Some(WithoutNiche::B(1)).vec(), [0, 1, 1]);
2302/// assert_eq!(None::<WithoutNiche>.vec(), [1]);
2303///
2304/// #[derive(Enum, ToOutput, MaybeHasNiche)]
2305/// #[enumtag("bool")]
2306/// #[niche(tag)]
2307/// enum WithBoolTag {
2308///     A(u8),
2309///     B(bool),
2310/// }
2311///
2312/// assert_eq!(Some(WithBoolTag::A(32)).vec(), [0, 32]);
2313/// assert_eq!(Some(WithBoolTag::B(true)).vec(), [1, 1]);
2314/// assert_eq!(None::<WithBoolTag>.vec(), [2]);
2315///
2316/// #[derive(Enum, ToOutput, MaybeHasNiche)]
2317/// #[enumtag("char")]
2318/// #[niche(tag)]
2319/// enum WithChar {
2320///     A(u8),
2321///     B(bool),
2322/// }
2323///
2324/// assert_eq!(Some(WithChar::A(32)).vec(), [0, 32]);
2325/// assert_eq!(Some(WithChar::B(true)).vec(), [1, 1]);
2326/// assert_eq!(None::<WithChar>.vec(), [255]);
2327/// ```
2328#[proc_macro_derive(Enum, attributes(enumtag))]
2329pub fn derive_enum(input: TokenStream) -> TokenStream {
2330    let input = parse_macro_input!(input as DeriveInput);
2331    let name = input.ident;
2332    let generics = input.generics.clone();
2333    let (_, ty_generics, _) = generics.split_for_impl();
2334    let generics = input.generics;
2335    let length = gen_length(&input.data);
2336    let variants = gen_variants(&input.data);
2337    let variant_count = gen_variant_count(&input.data);
2338    let to_tag = gen_to_tag(&input.data);
2339    let from_tag = gen_from_tag(&input.data);
2340    let kind = gen_kind(&input.data);
2341    let (impl_generics, _, where_clause) = generics.split_for_impl();
2342    let mut errors = Vec::new();
2343    let mut enumtag = None;
2344    for attr in &input.attrs {
2345        if attr_str(attr).as_deref() == Some("enumtag") {
2346            match parse_path(attr) {
2347                Ok(path) => {
2348                    if enumtag.is_some() {
2349                        errors.push(Error::new_spanned(path, "duplicate tag"));
2350                    } else {
2351                        enumtag = Some(path);
2352                    }
2353                }
2354                Err(e) => errors.push(e),
2355            }
2356        }
2357    }
2358    let enumtag = enumtag.unwrap_or_else(|| {
2359        parse_quote!(
2360            ::object_rainbow::partial_byte_tag::PartialByteTag<#length>
2361        )
2362    });
2363    let errors = errors.into_iter().map(|e| e.into_compile_error());
2364    let target = parse_for(&name, &input.attrs);
2365    let output = quote! {
2366        const _: () = {
2367            #(#errors)*
2368
2369            use ::object_rainbow::enumkind::EnumKind;
2370
2371            #[derive(
2372                ::core::clone::Clone,
2373                ::core::marker::Copy,
2374                ::object_rainbow::ParseAsInline,
2375            )]
2376            pub enum __Kind {
2377                #variants
2378            }
2379
2380            #[automatically_derived]
2381            impl ::object_rainbow::enumkind::EnumKind for __Kind {
2382                type Tag = ::object_rainbow::enumkind::EnumTag<
2383                    #enumtag,
2384                    #variant_count,
2385                >;
2386
2387                fn to_tag(self) -> Self::Tag {
2388                    #to_tag
2389                }
2390
2391                fn from_tag(tag: Self::Tag) -> Self {
2392                    #from_tag
2393                }
2394            }
2395
2396            impl<I: ::object_rainbow::ParseInput> ::object_rainbow::ParseInline<I> for __Kind {
2397                fn parse_inline(input: &mut I) -> ::object_rainbow::Result<Self> {
2398                    Ok(::object_rainbow::enumkind::EnumKind::from_tag(input.parse_inline()?))
2399                }
2400            }
2401
2402            impl ::object_rainbow::MaybeHasNiche for __Kind {
2403                type MnArray = <#enumtag as ::object_rainbow::MaybeHasNiche>::MnArray;
2404            }
2405
2406            #[automatically_derived]
2407            impl #impl_generics ::object_rainbow::Enum for #target #ty_generics #where_clause {
2408                type Kind = __Kind;
2409
2410                fn kind(&self) -> Self::Kind {
2411                    #kind
2412                }
2413            }
2414        };
2415    };
2416    TokenStream::from(output)
2417}
2418
2419fn gen_length(data: &Data) -> proc_macro2::TokenStream {
2420    match data {
2421        Data::Struct(data) => {
2422            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2423        }
2424        Data::Enum(data) => {
2425            let name = format!("U{}", data.variants.len());
2426            let ident = Ident::new(&name, data.variants.span());
2427            quote! { ::object_rainbow::typenum::#ident }
2428        }
2429        Data::Union(data) => {
2430            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2431        }
2432    }
2433}
2434
2435fn gen_variants(data: &Data) -> proc_macro2::TokenStream {
2436    match data {
2437        Data::Struct(data) => {
2438            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2439        }
2440        Data::Enum(data) => {
2441            let variants = data.variants.iter().map(|v| &v.ident);
2442            quote! { #(#variants),* }
2443        }
2444        Data::Union(data) => {
2445            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2446        }
2447    }
2448}
2449
2450fn gen_variant_count(data: &Data) -> proc_macro2::TokenStream {
2451    match data {
2452        Data::Struct(data) => {
2453            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2454        }
2455        Data::Enum(data) => {
2456            let variant_count = data.variants.len();
2457            quote! { #variant_count }
2458        }
2459        Data::Union(data) => {
2460            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2461        }
2462    }
2463}
2464
2465fn gen_to_tag(data: &Data) -> proc_macro2::TokenStream {
2466    match data {
2467        Data::Struct(data) => {
2468            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2469        }
2470        Data::Enum(data) => {
2471            let to_tag = data.variants.iter().enumerate().map(|(i, v)| {
2472                let ident = &v.ident;
2473                quote_spanned! { ident.span() =>
2474                    Self::#ident => ::object_rainbow::enumkind::EnumTag::from_const::<#i>(),
2475                }
2476            });
2477            quote! {
2478                match self {
2479                    #(#to_tag)*
2480                }
2481            }
2482        }
2483        Data::Union(data) => {
2484            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2485        }
2486    }
2487}
2488
2489fn gen_from_tag(data: &Data) -> proc_macro2::TokenStream {
2490    match data {
2491        Data::Struct(data) => {
2492            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2493        }
2494        Data::Enum(data) => {
2495            let from_tag = data.variants.iter().enumerate().map(|(i, v)| {
2496                let ident = &v.ident;
2497                quote_spanned! { ident.span() =>
2498                    #i => Self::#ident,
2499                }
2500            });
2501            quote! {
2502                match tag.to_usize() {
2503                    #(#from_tag)*
2504                    _ => unreachable!(),
2505                }
2506            }
2507        }
2508        Data::Union(data) => {
2509            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2510        }
2511    }
2512}
2513
2514fn gen_kind(data: &Data) -> proc_macro2::TokenStream {
2515    match data {
2516        Data::Struct(data) => {
2517            Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2518        }
2519        Data::Enum(data) => {
2520            if data.variants.is_empty() {
2521                return quote! {
2522                    match *self {}
2523                };
2524            }
2525            let variants = data.variants.iter().map(|v| {
2526                let ident = &v.ident;
2527                quote_spanned! { ident.span() =>
2528                    Self::#ident {..} => __Kind::#ident,
2529                }
2530            });
2531            quote! {
2532                match self {
2533                    #(#variants)*
2534                }
2535            }
2536        }
2537        Data::Union(data) => {
2538            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2539        }
2540    }
2541}
2542
2543/// ```rust
2544/// use object_rainbow::{MaybeHasNiche, Size};
2545///
2546/// #[derive(Size, MaybeHasNiche)]
2547/// struct WithHole(bool, u8);
2548///
2549/// #[derive(Size, MaybeHasNiche)]
2550/// struct NoHole(u8, u8);
2551///
2552/// assert_eq!(Option::<WithHole>::SIZE, 2);
2553/// assert_eq!(Option::<(object_rainbow::ff::Ff, NoHole)>::SIZE, 3);
2554/// ```
2555#[proc_macro_derive(MaybeHasNiche, attributes(niche))]
2556pub fn derive_maybe_has_niche(input: TokenStream) -> TokenStream {
2557    let input = parse_macro_input!(input as DeriveInput);
2558    let name = input.ident;
2559    let mn_array = gen_mn_array(&input.data, &input.attrs);
2560    let (_, ty_generics, _) = input.generics.split_for_impl();
2561    let generics = match bounds_maybe_has_niche(input.generics.clone(), &input.data, &input.attrs) {
2562        Ok(g) => g,
2563        Err(e) => return e.into_compile_error().into(),
2564    };
2565    let (impl_generics, _, where_clause) = generics.split_for_impl();
2566    let target = parse_for(&name, &input.attrs);
2567    let output = quote! {
2568        const _: () = {
2569            use ::object_rainbow::typenum::tarr;
2570
2571            #[automatically_derived]
2572            impl #impl_generics ::object_rainbow::MaybeHasNiche
2573            for #target #ty_generics #where_clause {
2574                type MnArray = #mn_array;
2575            }
2576        };
2577    };
2578    TokenStream::from(output)
2579}
2580
2581#[derive(Debug, FromMeta)]
2582#[darling(derive_syn_parse)]
2583struct ContainerNicheArgs {
2584    #[darling(default)]
2585    tag: bool,
2586}
2587
2588fn parse_niche_tag(attrs: &[Attribute]) -> syn::Result<bool> {
2589    let mut t = false;
2590    for attr in attrs {
2591        if attr_str(attr).as_deref() == Some("niche") {
2592            let ContainerNicheArgs { tag } = attr.parse_args()?;
2593            if tag {
2594                t = true;
2595            }
2596        }
2597    }
2598    Ok(t)
2599}
2600
2601fn bounds_maybe_has_niche(
2602    mut generics: Generics,
2603    data: &Data,
2604    attrs: &[Attribute],
2605) -> syn::Result<Generics> {
2606    let tag = parse_niche_tag(attrs)?;
2607    match data {
2608        Data::Struct(data) => {
2609            for f in data.fields.iter() {
2610                let ty = &f.ty;
2611                generics
2612                    .make_where_clause()
2613                    .predicates
2614                    .push(parse_quote_spanned! { ty.span() =>
2615                        #ty: ::object_rainbow::MaybeHasNiche<
2616                            MnArray: ::object_rainbow::MnArray<
2617                                MaybeNiche: ::object_rainbow::MaybeNiche
2618                            >
2619                        >
2620                    });
2621            }
2622        }
2623        Data::Enum(data) => {
2624            if tag {
2625                return Ok(generics);
2626            }
2627            generics.params.push(parse_quote!(
2628                __N: ::object_rainbow::typenum::Unsigned
2629            ));
2630            for (i, v) in data.variants.iter().enumerate() {
2631                let mn_array = fields_mn_array(&v.fields, Some(i));
2632                generics
2633                    .make_where_clause()
2634                    .predicates
2635                    .push(parse_quote_spanned! { v.span() =>
2636                        #mn_array: ::object_rainbow::MnArray<
2637                            MaybeNiche: ::object_rainbow::NicheOr<N = __N>
2638                        >
2639                    });
2640                for f in v.fields.iter() {
2641                    let ty = &f.ty;
2642                    generics.make_where_clause().predicates.push(
2643                        parse_quote_spanned! { ty.span() =>
2644                            #ty: ::object_rainbow::MaybeHasNiche<
2645                                MnArray: ::object_rainbow::MnArray<
2646                                    MaybeNiche: ::object_rainbow::MaybeNiche
2647                                >
2648                            >
2649                        },
2650                    );
2651                }
2652            }
2653        }
2654        Data::Union(data) => {
2655            return Err(Error::new_spanned(
2656                data.union_token,
2657                "`union`s are not supported",
2658            ));
2659        }
2660    }
2661    Ok(generics)
2662}
2663
2664fn fields_mn_array(fields: &syn::Fields, variant: Option<usize>) -> proc_macro2::TokenStream {
2665    let mn_array = fields.iter().map(|f| {
2666        let ty = &f.ty;
2667        quote! {
2668            <
2669                <
2670                    #ty
2671                    as
2672                    ::object_rainbow::MaybeHasNiche
2673                >::MnArray
2674                as
2675                ::object_rainbow::MnArray
2676            >::MaybeNiche
2677        }
2678    });
2679    if let Some(variant) = variant {
2680        let kind_niche = quote! {
2681            ::object_rainbow::AutoEnumNiche<Self, #variant>
2682        };
2683        quote! {
2684            tarr![
2685                #kind_niche,
2686                ::object_rainbow::NoNiche<::object_rainbow::HackNiche<#variant>>, #(#mn_array),*
2687            ]
2688        }
2689    } else {
2690        quote! { tarr![#(#mn_array),*] }
2691    }
2692}
2693
2694fn gen_mn_array(data: &Data, attrs: &[Attribute]) -> proc_macro2::TokenStream {
2695    let tag = match parse_niche_tag(attrs) {
2696        Ok(tag) => tag,
2697        Err(e) => return e.into_compile_error(),
2698    };
2699    match data {
2700        Data::Struct(data) => fields_mn_array(&data.fields, None),
2701        Data::Enum(data) => {
2702            if tag {
2703                return quote! {
2704                    <
2705                        <Self as ::object_rainbow::Enum>::Kind as ::object_rainbow::MaybeHasNiche
2706                    >::MnArray
2707                };
2708            }
2709            let mn_array = data.variants.iter().enumerate().map(|(i, v)| {
2710                let mn_array = fields_mn_array(&v.fields, Some(i));
2711                quote! { <#mn_array as ::object_rainbow::MnArray>::MaybeNiche }
2712            });
2713            quote! {
2714                ::object_rainbow::NicheFoldOrArray<tarr![#(#mn_array),*]>
2715            }
2716        }
2717        Data::Union(data) => {
2718            Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
2719        }
2720    }
2721}
2722
2723#[proc_macro_derive(CanonicalExtra)]
2724pub fn derive_canonical_extra(input: TokenStream) -> TokenStream {
2725    let input = parse_macro_input!(input as DeriveInput);
2726    let name = input.ident;
2727    let generics = input.generics.clone();
2728    let (_, ty_generics, _) = generics.split_for_impl();
2729    let generics = match bounds_canonical_extra(input.generics, &input.data) {
2730        Ok(g) => g,
2731        Err(e) => return e.into_compile_error().into(),
2732    };
2733    let (impl_generics, _, where_clause) = generics.split_for_impl();
2734    let target = parse_for(&name, &input.attrs);
2735    let output = quote! {
2736        #[automatically_derived]
2737        impl #impl_generics ::object_rainbow::CanonicalExtra for #target #ty_generics #where_clause {
2738            type Extra = __Extra;
2739        }
2740    };
2741    TokenStream::from(output)
2742}
2743
2744#[proc_macro_derive(ToCanonicalExtra)]
2745pub fn derive_to_canonical_extra(input: TokenStream) -> TokenStream {
2746    let input = parse_macro_input!(input as DeriveInput);
2747    let name = input.ident;
2748    let generics = input.generics.clone();
2749    let (_, ty_generics, _) = generics.split_for_impl();
2750    let generics = match bounds_to_canonical_extra(input.generics, &input.data) {
2751        Ok(g) => g,
2752        Err(e) => return e.into_compile_error().into(),
2753    };
2754    let canonical_extra = gen_canonical_extra(&input.data);
2755    let (impl_generics, _, where_clause) = generics.split_for_impl();
2756    let target = parse_for(&name, &input.attrs);
2757    let output = quote! {
2758        #[automatically_derived]
2759        impl #impl_generics ::object_rainbow::ToCanonicalExtra for #target #ty_generics #where_clause {
2760            fn canonical_extra(&self) -> Self::Extra {
2761                #canonical_extra
2762            }
2763        }
2764    };
2765    TokenStream::from(output)
2766}
2767
2768fn bounds_canonical_extra(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
2769    match data {
2770        Data::Struct(data) => {
2771            if let Some(f) = data.fields.iter().next() {
2772                let ty = &f.ty;
2773                generics
2774                    .make_where_clause()
2775                    .predicates
2776                    .push(parse_quote_spanned! { ty.span() =>
2777                        #ty: ::object_rainbow::CanonicalExtra<Extra = __Extra>
2778                    });
2779            }
2780        }
2781        Data::Enum(data) => {
2782            for variant in &data.variants {
2783                if let Some(f) = variant.fields.iter().next() {
2784                    let ty = &f.ty;
2785                    generics.make_where_clause().predicates.push(
2786                        parse_quote_spanned! { ty.span() =>
2787                            #ty: ::object_rainbow::CanonicalExtra<Extra = __Extra>
2788                        },
2789                    );
2790                }
2791            }
2792        }
2793        Data::Union(data) => {
2794            return Err(Error::new_spanned(
2795                data.union_token,
2796                "`union`s are not supported",
2797            ));
2798        }
2799    }
2800    generics.params.push(parse_quote!(__Extra));
2801    Ok(generics)
2802}
2803
2804fn bounds_to_canonical_extra(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
2805    match data {
2806        Data::Struct(data) => {
2807            if let Some(f) = data.fields.iter().next() {
2808                let ty = &f.ty;
2809                generics
2810                    .make_where_clause()
2811                    .predicates
2812                    .push(parse_quote_spanned! { ty.span() =>
2813                        #ty: ::object_rainbow::ToCanonicalExtra<Extra = __Extra>
2814                    });
2815            }
2816        }
2817        Data::Enum(data) => {
2818            for variant in &data.variants {
2819                if let Some(f) = variant.fields.iter().next() {
2820                    let ty = &f.ty;
2821                    generics.make_where_clause().predicates.push(
2822                        parse_quote_spanned! { ty.span() =>
2823                            #ty: ::object_rainbow::ToCanonicalExtra<Extra = __Extra>
2824                        },
2825                    );
2826                }
2827            }
2828        }
2829        Data::Union(data) => {
2830            return Err(Error::new_spanned(
2831                data.union_token,
2832                "`union`s are not supported",
2833            ));
2834        }
2835    }
2836    generics.params.push(parse_quote!(__Extra));
2837    Ok(generics)
2838}
2839
2840fn fields_canonical_extra(
2841    fields: &syn::Fields,
2842    unit_span: Option<Span>,
2843) -> proc_macro2::TokenStream {
2844    match fields {
2845        syn::Fields::Named(fields) => {
2846            if let Some(f) = fields.named.iter().next() {
2847                let ident = f.ident.as_ref().unwrap();
2848                quote! {
2849                    { #ident, .. }
2850                        => ::object_rainbow::ToCanonicalExtra::canonical_extra(#ident),
2851                }
2852            } else {
2853                let span = fields.brace_token.span.close();
2854                syn::Error::new(span, "no fields").into_compile_error()
2855            }
2856        }
2857        syn::Fields::Unnamed(fields) => {
2858            if !fields.unnamed.is_empty() {
2859                quote! {
2860                    (__first, ..)
2861                        => ::object_rainbow::ToCanonicalExtra::canonical_extra(__first),
2862                }
2863            } else {
2864                let span = fields.paren_token.span.close();
2865                syn::Error::new(span, "no fields").into_compile_error()
2866            }
2867        }
2868        syn::Fields::Unit => syn::Error::new(unit_span.unwrap(), "no fields").into_compile_error(),
2869    }
2870}
2871
2872fn gen_canonical_extra(data: &Data) -> proc_macro2::TokenStream {
2873    match data {
2874        Data::Struct(data) => {
2875            let arm = fields_canonical_extra(&data.fields, data.semi_token.map(|x| x.span));
2876            quote! {
2877                match self {
2878                    Self #arm
2879                }
2880            }
2881        }
2882        Data::Enum(data) => {
2883            let arms = data.variants.iter().map(|variant| {
2884                let ident = &variant.ident;
2885                let arm = fields_canonical_extra(&variant.fields, Some(ident.span()));
2886                quote! {
2887                    Self::#ident #arm
2888                }
2889            });
2890            quote! {
2891                match self {
2892                    #(#arms)*
2893                }
2894            }
2895        }
2896        Data::Union(data) => {
2897            Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2898        }
2899    }
2900}
2901
2902#[proc_macro_attribute]
2903pub fn derive_for_wrapped(args: TokenStream, input: TokenStream) -> TokenStream {
2904    let input = parse_macro_input!(input as ItemTrait);
2905    let sup = if args.is_empty() {
2906        let sup = input.supertraits.clone();
2907        quote!(#sup)
2908    } else {
2909        args.into()
2910    };
2911    let name = input.ident.clone();
2912    let generics = input.generics.clone();
2913    let (_, ty_generics, _) = generics.split_for_impl();
2914    let mut derived = Vec::new();
2915    for (path, extra) in [
2916        (
2917            quote!(map_extra::MappedExtra),
2918            vec![(quote!(__M), quote!(#sup))],
2919        ),
2920        (quote!(length_prefixed::Lp), vec![]),
2921    ] {
2922        let mut generics = input.generics.clone();
2923        generics.params.push(parse_quote! {
2924            __T: #name #ty_generics
2925        });
2926        for (i, ty) in &extra {
2927            generics.params.push(parse_quote! {
2928                #i: #ty
2929            });
2930        }
2931        let (impl_generics, _, where_clause) = generics.split_for_impl();
2932        let i = input
2933            .items
2934            .clone()
2935            .into_iter()
2936            .map(|i| match i {
2937                TraitItem::Const(i) => ImplItem::Const({
2938                    let const_token = i.const_token;
2939                    let ident = i.ident;
2940                    let colon_token = i.colon_token;
2941                    let ty = i.ty;
2942                    let semi_token = i.semi_token;
2943                    parse_quote! {
2944                        #const_token
2945                        #ident
2946                        #colon_token
2947                        #ty
2948                        =
2949                        <__T as #name #ty_generics>::#ident
2950                        #semi_token
2951                    }
2952                }),
2953                TraitItem::Fn(i) => ImplItem::Fn({
2954                    let mut sig = i.sig;
2955                    let ident = sig.ident.clone();
2956                    let args = sig
2957                        .inputs
2958                        .iter_mut()
2959                        .enumerate()
2960                        .map(|(n, i)| match i {
2961                            FnArg::Receiver(receiver) => {
2962                                let reference = receiver.reference.as_ref().map(|(and, _)| and);
2963                                let mutability = receiver.mutability.as_ref();
2964                                let ident = &receiver.self_token;
2965                                quote!(#reference #mutability *#ident)
2966                            }
2967                            FnArg::Typed(pat_type) => {
2968                                let ident = Ident::new(&format!("arg{n}"), pat_type.span());
2969                                *pat_type.pat = parse_quote!(#ident);
2970                                quote!(#ident)
2971                            }
2972                        })
2973                        .collect::<Vec<_>>();
2974                    parse_quote! {
2975                        #sig
2976                        {
2977                            <__T as #name #ty_generics>::#ident(
2978                                #(#args),*
2979                            )
2980                        }
2981                    }
2982                }),
2983                TraitItem::Type(i) => ImplItem::Type({
2984                    let type_token = i.type_token;
2985                    let ident = i.ident;
2986                    let semi_token = i.semi_token;
2987                    parse_quote! {
2988                        #type_token
2989                        #ident
2990                        =
2991                        <__T as #name #ty_generics>::#ident
2992                        #semi_token
2993                    }
2994                }),
2995                _ => unimplemented!("unknown/unsupported item"),
2996            })
2997            .collect::<Vec<_>>();
2998        let extra = extra.into_iter().map(|(k, _)| k);
2999        derived.push(quote! {
3000            #[automatically_derived]
3001            impl #impl_generics #name #ty_generics for ::object_rainbow::#path<
3002                __T,
3003                #(#extra),*
3004            >
3005            #where_clause
3006            {
3007                #(#i)*
3008            }
3009        });
3010    }
3011    let output = quote! {
3012        #input
3013
3014        #(#derived)*
3015    };
3016    output.into()
3017}
3018
3019#[derive(Debug, FromMeta, Default)]
3020#[darling(derive_syn_parse)]
3021struct PodArgs {
3022    #[darling(default)]
3023    no_clone: SpannedValue<bool>,
3024    #[darling(default)]
3025    no_copy: SpannedValue<bool>,
3026    #[darling(default)]
3027    no_default: SpannedValue<bool>,
3028    #[darling(default)]
3029    no_size: SpannedValue<bool>,
3030    #[darling(default)]
3031    no_niche: SpannedValue<bool>,
3032    #[darling(default)]
3033    no_output: SpannedValue<bool>,
3034    #[darling(default)]
3035    no_tagged: SpannedValue<bool>,
3036    #[darling(default)]
3037    no_parse: SpannedValue<bool>,
3038    #[darling(default)]
3039    no_inline: SpannedValue<bool>,
3040    #[darling(default)]
3041    no_inline_output: SpannedValue<bool>,
3042    #[darling(default)]
3043    no_byte_ord: SpannedValue<bool>,
3044}
3045
3046#[proc_macro_attribute]
3047pub fn pod(args: TokenStream, input: TokenStream) -> TokenStream {
3048    let (
3049        PodArgs {
3050            no_clone,
3051            no_copy,
3052            no_default,
3053            no_size,
3054            no_niche,
3055            no_output,
3056            no_tagged,
3057            no_parse,
3058            no_inline,
3059            no_inline_output,
3060            no_byte_ord,
3061        },
3062        args_error,
3063    ) = match syn::parse(args) {
3064        Ok(args) => (args, Default::default()),
3065        Err(e) => (Default::default(), e.into_compile_error()),
3066    };
3067    let thing = proc_macro2::TokenStream::from(input);
3068    let derive_enum = match syn::parse2::<Item>(thing.clone()) {
3069        Ok(Item::Struct(_)) => Ok(quote! {}),
3070        Ok(Item::Enum(_)) => Ok(quote! {
3071            ::object_rainbow::Enum,
3072        }),
3073        Ok(_) => Err(syn::Error::new(thing.span(), "not `struct` or `enum`")),
3074        Err(e) => Err(e),
3075    }
3076    .unwrap_or_else(|e| e.into_compile_error());
3077    let yes_clone = !no_clone.into_inner();
3078    let yes_copy = !no_copy.into_inner();
3079    let derive_clone = if yes_clone {
3080        quote! {
3081            ::core::clone::Clone,
3082        }
3083    } else {
3084        quote! {}
3085    };
3086    let derive_copy = if yes_clone && yes_copy {
3087        quote! {
3088            ::core::marker::Copy,
3089        }
3090    } else {
3091        quote! {}
3092    };
3093    let derive_default = if no_default.into_inner() {
3094        quote! {}
3095    } else {
3096        quote! {
3097            ::core::default::Default,
3098        }
3099    };
3100    let derive_tagged = if no_tagged.into_inner() {
3101        quote! {}
3102    } else {
3103        quote! {
3104            ::object_rainbow::Tagged,
3105        }
3106    };
3107    let yes_output = !no_output.into_inner();
3108    let yes_parse = !no_parse.into_inner();
3109    let yes_inline = !no_inline.into_inner();
3110    let yes_inline_output = !no_inline_output.into_inner();
3111    let yes_byte_ord = !no_byte_ord.into_inner();
3112    let yes_size = !no_size.into_inner();
3113    let yes_niche = !no_niche.into_inner();
3114    let derive_to_output = if yes_output {
3115        quote! {
3116            ::object_rainbow::ToOutput,
3117        }
3118    } else {
3119        quote! {}
3120    };
3121    let derive_inline_output = if yes_output && yes_inline && yes_inline_output {
3122        quote! {
3123            ::object_rainbow::InlineOutput,
3124        }
3125    } else {
3126        quote! {}
3127    };
3128    let derive_byte_ord = if yes_output && yes_byte_ord {
3129        quote! {
3130            ::object_rainbow::ByteOrd,
3131        }
3132    } else {
3133        quote! {}
3134    };
3135    let derive_parse = if yes_parse {
3136        quote! {
3137            ::object_rainbow::Parse,
3138        }
3139    } else {
3140        quote! {}
3141    };
3142    let derive_parse_inline = if yes_parse && yes_inline {
3143        quote! {
3144            ::object_rainbow::ParseInline,
3145        }
3146    } else {
3147        quote! {}
3148    };
3149    let derive_size = if yes_size && yes_output {
3150        quote! {
3151            ::object_rainbow::Size,
3152        }
3153    } else {
3154        quote! {}
3155    };
3156    let derive_niche = if yes_niche && yes_output {
3157        quote! {
3158            ::object_rainbow::MaybeHasNiche,
3159        }
3160    } else {
3161        quote! {}
3162    };
3163    let thing = quote! {
3164        #args_error
3165        #[derive(
3166            #derive_enum
3167            #derive_clone
3168            #derive_copy
3169            ::core::cmp::PartialEq,
3170            ::core::cmp::Eq,
3171            ::core::cmp::PartialOrd,
3172            ::core::cmp::Ord,
3173            #derive_default
3174            ::core::fmt::Debug,
3175            ::core::hash::Hash,
3176            #derive_to_output
3177            #derive_inline_output
3178            #derive_byte_ord
3179            #derive_tagged
3180            ::object_rainbow::ListHashes,
3181            ::object_rainbow::Topological,
3182            #derive_parse
3183            #derive_parse_inline
3184            #derive_size
3185            #derive_niche
3186        )]
3187        #thing
3188    };
3189    thing.into()
3190}