1use std::collections::BTreeSet;
2
3use proc_macro::TokenStream;
4use quote::{quote, quote_spanned};
5use syn::{
6 AngleBracketedGenericArguments, Attribute, Data, DeriveInput, Error, Expr, GenericParam,
7 Generics, Ident, LitStr, Path, Type, parse::Parse, parse_macro_input, parse_quote,
8 parse_quote_spanned, spanned::Spanned, token::Comma,
9};
10
11fn expr_contains_generics(g: &BTreeSet<Ident>, expr: &Expr) -> bool {
12 match expr {
13 Expr::Path(expr) => path_contains_generics(g, &expr.path),
14 _ => unimplemented!(),
15 }
16}
17
18fn args_contains_generics(g: &BTreeSet<Ident>, args: &AngleBracketedGenericArguments) -> bool {
19 args.args.iter().any(|arg| match arg {
20 syn::GenericArgument::Type(ty) => type_contains_generics(g, ty),
21 syn::GenericArgument::AssocType(ty) => {
22 ty.generics
23 .as_ref()
24 .is_some_and(|args| args_contains_generics(g, args))
25 || type_contains_generics(g, &ty.ty)
26 }
27 syn::GenericArgument::Const(expr) => expr_contains_generics(g, expr),
28 syn::GenericArgument::AssocConst(expr) => {
29 expr.generics
30 .as_ref()
31 .is_some_and(|args| args_contains_generics(g, args))
32 || expr_contains_generics(g, &expr.value)
33 }
34 _ => false,
35 })
36}
37
38fn path_contains_generics(g: &BTreeSet<Ident>, path: &Path) -> bool {
39 path.segments.iter().any(|seg| match &seg.arguments {
40 syn::PathArguments::None => g.contains(&seg.ident),
41 syn::PathArguments::AngleBracketed(args) => args_contains_generics(g, args),
42 syn::PathArguments::Parenthesized(args) => {
43 args.inputs.iter().any(|ty| type_contains_generics(g, ty))
44 || match &args.output {
45 syn::ReturnType::Default => false,
46 syn::ReturnType::Type(_, ty) => type_contains_generics(g, ty),
47 }
48 }
49 })
50}
51
52fn type_contains_generics(g: &BTreeSet<Ident>, ty: &Type) -> bool {
53 match ty {
54 Type::Array(ty) => type_contains_generics(g, &ty.elem),
55 Type::BareFn(ty) => {
56 ty.inputs.iter().any(|a| type_contains_generics(g, &a.ty))
57 || match &ty.output {
58 syn::ReturnType::Default => false,
59 syn::ReturnType::Type(_, ty) => type_contains_generics(g, ty),
60 }
61 }
62 Type::Group(ty) => type_contains_generics(g, &ty.elem),
63 Type::Macro(_) => true,
64 Type::Paren(ty) => type_contains_generics(g, &ty.elem),
65 Type::Path(ty) => path_contains_generics(g, &ty.path),
66 Type::Reference(ty) => type_contains_generics(g, &ty.elem),
67 Type::Slice(ty) => type_contains_generics(g, &ty.elem),
68 Type::Tuple(ty) => ty.elems.iter().any(|ty| type_contains_generics(g, ty)),
69 _ => false,
70 }
71}
72
73fn bounds_g(generics: &Generics) -> BTreeSet<Ident> {
74 generics
75 .params
76 .iter()
77 .filter_map(|param| match param {
78 GenericParam::Lifetime(_) => None,
79 GenericParam::Type(param) => Some(¶m.ident),
80 GenericParam::Const(param) => Some(¶m.ident),
81 })
82 .cloned()
83 .collect()
84}
85
86#[proc_macro_derive(ToOutput)]
87pub fn derive_to_output(input: TokenStream) -> TokenStream {
88 let input = parse_macro_input!(input as DeriveInput);
89 let name = input.ident;
90 let generics = match bounds_to_output(input.generics, &input.data) {
91 Ok(g) => g,
92 Err(e) => return e.into_compile_error().into(),
93 };
94 let to_output = gen_to_output(&input.data);
95 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
96 let output = quote! {
97 impl #impl_generics ::object_rainbow::ToOutput for #name #ty_generics #where_clause {
98 fn to_output(&self, output: &mut dyn ::object_rainbow::Output) {
99 #to_output
100 }
101 }
102 };
103 TokenStream::from(output)
104}
105
106fn bounds_to_output(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
107 let g = bounds_g(&generics);
108 match data {
109 Data::Struct(data) => {
110 for f in data.fields.iter() {
111 let ty = &f.ty;
112 if type_contains_generics(&g, ty) {
113 generics.make_where_clause().predicates.push(
114 parse_quote_spanned! { ty.span() =>
115 #ty: ::object_rainbow::ToOutput
116 },
117 );
118 }
119 }
120 }
121 Data::Enum(data) => {
122 for v in data.variants.iter() {
123 for f in v.fields.iter() {
124 let ty = &f.ty;
125 if type_contains_generics(&g, ty) {
126 generics.make_where_clause().predicates.push(
127 parse_quote_spanned! { ty.span() =>
128 #ty: ::object_rainbow::ToOutput
129 },
130 );
131 }
132 }
133 }
134 }
135 Data::Union(data) => {
136 return Err(Error::new_spanned(
137 data.union_token,
138 "`union`s are not supported",
139 ));
140 }
141 }
142 Ok(generics)
143}
144
145fn fields_to_output(fields: &syn::Fields) -> proc_macro2::TokenStream {
146 match fields {
147 syn::Fields::Named(fields) => {
148 let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
149 let to_output = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
150 quote_spanned! { f.ty.span() =>
151 #i.to_output(output)
152 }
153 });
154 quote! {
155 { #(#let_self),* } => {
156 #(#to_output);*
157 }
158 }
159 }
160 syn::Fields::Unnamed(fields) => {
161 let let_self = fields
162 .unnamed
163 .iter()
164 .enumerate()
165 .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
166 let to_output = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
167 quote_spanned! { f.ty.span() =>
168 #i.to_output(output)
169 }
170 });
171 quote! {
172 (#(#let_self),*) => {
173 #(#to_output);*
174 }
175 }
176 }
177 syn::Fields::Unit => quote! {
178 => {}
179 },
180 }
181}
182
183fn gen_to_output(data: &Data) -> proc_macro2::TokenStream {
184 match data {
185 Data::Struct(data) => {
186 let arm = fields_to_output(&data.fields);
187 quote! {
188 match self {
189 Self #arm
190 }
191 }
192 }
193 Data::Enum(data) => {
194 let to_output = data.variants.iter().map(|v| {
195 let ident = &v.ident;
196 let arm = fields_to_output(&v.fields);
197 quote! { Self::#ident #arm }
198 });
199 quote! {
200 let kind = ::object_rainbow::Enum::kind(self);
201 let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
202 tag.to_output(output);
203 match self {
204 #(#to_output)*
205 }
206 }
207 }
208 Data::Union(data) => {
209 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
210 }
211 }
212}
213
214#[proc_macro_derive(Topological)]
215pub fn derive_topological(input: TokenStream) -> TokenStream {
216 let input = parse_macro_input!(input as DeriveInput);
217 let name = input.ident;
218 let generics = match bounds_topological(input.generics, &input.data) {
219 Ok(g) => g,
220 Err(e) => return e.into_compile_error().into(),
221 };
222 let accept_points = gen_accept_points(&input.data);
223 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
224 let output = quote! {
225 impl #impl_generics ::object_rainbow::Topological for #name #ty_generics #where_clause {
226 fn accept_points(&self, visitor: &mut impl ::object_rainbow::PointVisitor) {
227 #accept_points
228 }
229 }
230 };
231 TokenStream::from(output)
232}
233
234fn bounds_topological(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
235 let g = bounds_g(&generics);
236 match data {
237 Data::Struct(data) => {
238 for f in data.fields.iter() {
239 let ty = &f.ty;
240 if type_contains_generics(&g, ty) {
241 generics.make_where_clause().predicates.push(
242 parse_quote_spanned! { ty.span() =>
243 #ty: ::object_rainbow::Topological
244 },
245 );
246 }
247 }
248 }
249 Data::Enum(data) => {
250 for v in data.variants.iter() {
251 for f in v.fields.iter() {
252 let ty = &f.ty;
253 if type_contains_generics(&g, ty) {
254 generics.make_where_clause().predicates.push(
255 parse_quote_spanned! { ty.span() =>
256 #ty: ::object_rainbow::Topological
257 },
258 );
259 }
260 }
261 }
262 }
263 Data::Union(data) => {
264 return Err(Error::new_spanned(
265 data.union_token,
266 "`union`s are not supported",
267 ));
268 }
269 }
270 Ok(generics)
271}
272
273fn fields_accept_points(fields: &syn::Fields) -> proc_macro2::TokenStream {
274 match fields {
275 syn::Fields::Named(fields) => {
276 let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
277 let accept_points = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
278 quote_spanned! { f.ty.span() =>
279 #i.accept_points(visitor)
280 }
281 });
282 quote! {
283 { #(#let_self),* } => {
284 #(#accept_points);*
285 }
286 }
287 }
288 syn::Fields::Unnamed(fields) => {
289 let let_self = fields
290 .unnamed
291 .iter()
292 .enumerate()
293 .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
294 let accept_points = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
295 quote_spanned! { f.ty.span() =>
296 #i.accept_points(visitor)
297 }
298 });
299 quote! {
300 (#(#let_self),*) => {
301 #(#accept_points);*
302 }
303 }
304 }
305 syn::Fields::Unit => quote! {
306 => {}
307 },
308 }
309}
310
311fn gen_accept_points(data: &Data) -> proc_macro2::TokenStream {
312 match data {
313 Data::Struct(data) => {
314 let arm = fields_accept_points(&data.fields);
315 quote! {
316 match self {
317 Self #arm
318 }
319 }
320 }
321 Data::Enum(data) => {
322 let to_output = data.variants.iter().map(|v| {
323 let ident = &v.ident;
324 let arm = fields_accept_points(&v.fields);
325 quote! { Self::#ident #arm }
326 });
327 quote! {
328 let kind = ::object_rainbow::Enum::kind(self);
329 let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
330 tag.accept_points(visitor);
331 match self {
332 #(#to_output)*
333 }
334 }
335 }
336 Data::Union(data) => {
337 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
338 }
339 }
340}
341
342#[proc_macro_derive(Tagged, attributes(tags))]
343pub fn derive_tagged(input: TokenStream) -> TokenStream {
344 let input = parse_macro_input!(input as DeriveInput);
345 let name = input.ident;
346 let mut errors = Vec::new();
347 let generics = match bounds_tagged(input.generics, &input.data, &mut errors) {
348 Ok(g) => g,
349 Err(e) => return e.into_compile_error().into(),
350 };
351 let tags = gen_tags(&input.data, &input.attrs, &mut errors);
352 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
353 let errors = errors.into_iter().map(|e| e.into_compile_error());
354 let output = quote! {
355 #(#errors)*
356
357 impl #impl_generics ::object_rainbow::Tagged for #name #ty_generics #where_clause {
358 const TAGS: ::object_rainbow::Tags = #tags;
359 }
360 };
361 TokenStream::from(output)
362}
363
364struct FieldTagArgs {
365 skip: bool,
366}
367
368impl Parse for FieldTagArgs {
369 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
370 let mut skip = false;
371 while !input.is_empty() {
372 let ident = input.parse::<Ident>()?;
373 if ident.to_string().as_str() != "skip" {
374 return Err(Error::new(ident.span(), "expected: skip"));
375 }
376 skip = true;
377 if !input.is_empty() {
378 input.parse::<Comma>()?;
379 }
380 }
381 Ok(Self { skip })
382 }
383}
384
385fn bounds_tagged(
386 mut generics: Generics,
387 data: &Data,
388 errors: &mut Vec<Error>,
389) -> syn::Result<Generics> {
390 let g = bounds_g(&generics);
391 match data {
392 Data::Struct(data) => {
393 for f in data.fields.iter() {
394 let mut skip = false;
395 for attr in &f.attrs {
396 if attr_str(attr).as_deref() == Some("tags") {
397 match attr.parse_args::<FieldTagArgs>() {
398 Ok(args) => skip |= args.skip,
399 Err(e) => errors.push(e),
400 }
401 }
402 }
403 if !skip {
404 let ty = &f.ty;
405 if type_contains_generics(&g, ty) {
406 generics.make_where_clause().predicates.push(
407 parse_quote_spanned! { ty.span() =>
408 #ty: ::object_rainbow::Tagged
409 },
410 );
411 }
412 }
413 }
414 }
415 Data::Enum(data) => {
416 for v in data.variants.iter() {
417 for f in v.fields.iter() {
418 let mut skip = false;
419 for attr in &f.attrs {
420 if attr_str(attr).as_deref() == Some("tags") {
421 match attr.parse_args::<FieldTagArgs>() {
422 Ok(args) => skip |= args.skip,
423 Err(e) => errors.push(e),
424 }
425 }
426 }
427 if !skip {
428 let ty = &f.ty;
429 if type_contains_generics(&g, ty) {
430 generics.make_where_clause().predicates.push(
431 parse_quote_spanned! { ty.span() =>
432 #ty: ::object_rainbow::Tagged
433 },
434 );
435 }
436 }
437 }
438 }
439 }
440 Data::Union(data) => {
441 return Err(Error::new_spanned(
442 data.union_token,
443 "`union`s are not supported",
444 ));
445 }
446 }
447 Ok(generics)
448}
449
450struct StructTagArgs {
451 tags: Vec<LitStr>,
452}
453
454impl Parse for StructTagArgs {
455 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
456 let mut tags = Vec::new();
457 while !input.is_empty() {
458 let tag = input.parse::<LitStr>()?;
459 tags.push(tag);
460 if !input.is_empty() {
461 input.parse::<Comma>()?;
462 }
463 }
464 Ok(Self { tags })
465 }
466}
467
468fn fields_tags(fields: &syn::Fields) -> Vec<proc_macro2::TokenStream> {
469 fields
470 .iter()
471 .filter_map(|f| {
472 let mut skip = false;
473 for attr in &f.attrs {
474 if attr_str(attr).as_deref() == Some("tags") {
475 skip |= attr.parse_args::<FieldTagArgs>().ok()?.skip;
476 }
477 }
478 let ty = &f.ty;
479 (!skip).then_some(quote! { <#ty as ::object_rainbow::Tagged>::TAGS })
480 })
481 .collect()
482}
483
484fn gen_tags(data: &Data, attrs: &[Attribute], errors: &mut Vec<Error>) -> proc_macro2::TokenStream {
485 match data {
486 Data::Struct(data) => {
487 let mut tags = Vec::new();
488 for attr in attrs {
489 if attr_str(attr).as_deref() == Some("tags") {
490 match attr.parse_args::<StructTagArgs>() {
491 Ok(mut args) => tags.append(&mut args.tags),
492 Err(e) => errors.push(e),
493 }
494 }
495 }
496 let nested = fields_tags(&data.fields);
497 if nested.len() == 1 && tags.is_empty() {
498 let nested = nested.into_iter().next().unwrap();
499 quote! {
500 #nested
501 }
502 } else {
503 quote! {
504 ::object_rainbow::Tags(&[#(#tags),*], &[#(&#nested),*])
505 }
506 }
507 }
508 Data::Enum(data) => {
509 let mut tags = Vec::new();
510 for attr in attrs {
511 if attr_str(attr).as_deref() == Some("tags") {
512 match attr.parse_args::<StructTagArgs>() {
513 Ok(mut args) => tags.append(&mut args.tags),
514 Err(e) => errors.push(e),
515 }
516 }
517 }
518 let mut nested: Vec<_> = data
519 .variants
520 .iter()
521 .flat_map(|v| fields_tags(&v.fields))
522 .collect();
523 let kind_tags = quote! {
524 <
525 <
526 <
527 Self
528 as
529 ::object_rainbow::Enum
530 >::Kind
531 as
532 ::object_rainbow::enumkind::EnumKind
533 >::Tag
534 as ::object_rainbow::Tagged
535 >::TAGS
536 };
537 nested.insert(0, kind_tags);
538 if nested.len() == 1 && tags.is_empty() {
539 let nested = nested.into_iter().next().unwrap();
540 quote! {
541 #nested
542 }
543 } else {
544 quote! {
545 ::object_rainbow::Tags(&[#(#tags),*], &[#(&#nested),*])
546 }
547 }
548 }
549 Data::Union(data) => {
550 Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
551 }
552 }
553}
554
555#[proc_macro_derive(Object)]
556pub fn derive_object(input: TokenStream) -> TokenStream {
557 let input = parse_macro_input!(input as DeriveInput);
558 let name = input.ident;
559 let generics = match bounds_object(input.generics, &input.data) {
560 Ok(g) => g,
561 Err(e) => return e.into_compile_error().into(),
562 };
563 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
564 let output = quote! {
565 impl #impl_generics ::object_rainbow::Object for #name #ty_generics #where_clause {}
566 };
567 TokenStream::from(output)
568}
569
570fn bounds_object(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
571 let g = bounds_g(&generics);
572 match data {
573 Data::Struct(data) => {
574 let last_at = data.fields.len().checked_sub(1).unwrap_or_default();
575 for (i, f) in data.fields.iter().enumerate() {
576 let last = i == last_at;
577 let ty = &f.ty;
578 let tr = if last {
579 quote!(::object_rainbow::Object)
580 } else {
581 quote!(::object_rainbow::Inline)
582 };
583 if type_contains_generics(&g, ty) {
584 generics.make_where_clause().predicates.push(
585 parse_quote_spanned! { ty.span() =>
586 #ty: #tr
587 },
588 );
589 }
590 }
591 }
592 Data::Enum(data) => {
593 for v in data.variants.iter() {
594 let last_at = v.fields.len().checked_sub(1).unwrap_or_default();
595 for (i, f) in v.fields.iter().enumerate() {
596 let last = i == last_at;
597 let ty = &f.ty;
598 let tr = if last {
599 quote!(::object_rainbow::Object)
600 } else {
601 quote!(::object_rainbow::Inline)
602 };
603 if type_contains_generics(&g, ty) {
604 generics.make_where_clause().predicates.push(
605 parse_quote_spanned! { ty.span() =>
606 #ty: #tr
607 },
608 );
609 }
610 }
611 }
612 }
613 Data::Union(data) => {
614 return Err(Error::new_spanned(
615 data.union_token,
616 "`union`s are not supported",
617 ));
618 }
619 }
620 Ok(generics)
621}
622
623#[proc_macro_derive(Inline)]
624pub fn derive_inline(input: TokenStream) -> TokenStream {
625 let input = parse_macro_input!(input as DeriveInput);
626 let name = input.ident;
627 let generics = match bounds_inline(input.generics, &input.data) {
628 Ok(g) => g,
629 Err(e) => return e.into_compile_error().into(),
630 };
631 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
632 let output = quote! {
633 impl #impl_generics ::object_rainbow::Inline for #name #ty_generics #where_clause {}
634 };
635 TokenStream::from(output)
636}
637
638fn bounds_inline(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
639 let g = bounds_g(&generics);
640 match data {
641 Data::Struct(data) => {
642 for f in data.fields.iter() {
643 let ty = &f.ty;
644 if type_contains_generics(&g, ty) {
645 generics.make_where_clause().predicates.push(
646 parse_quote_spanned! { ty.span() =>
647 #ty: ::object_rainbow::Inline
648 },
649 );
650 }
651 }
652 }
653 Data::Enum(data) => {
654 for v in data.variants.iter() {
655 for f in v.fields.iter() {
656 let ty = &f.ty;
657 if type_contains_generics(&g, ty) {
658 generics.make_where_clause().predicates.push(
659 parse_quote_spanned! { ty.span() =>
660 #ty: ::object_rainbow::Inline
661 },
662 );
663 }
664 }
665 }
666 }
667 Data::Union(data) => {
668 return Err(Error::new_spanned(
669 data.union_token,
670 "`union`s are not supported",
671 ));
672 }
673 }
674 Ok(generics)
675}
676
677#[proc_macro_derive(ReflessObject)]
678pub fn derive_refless_object(input: TokenStream) -> TokenStream {
679 let input = parse_macro_input!(input as DeriveInput);
680 let name = input.ident;
681 let generics = match bounds_refless_object(input.generics, &input.data) {
682 Ok(g) => g,
683 Err(e) => return e.into_compile_error().into(),
684 };
685 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
686 let output = quote! {
687 impl #impl_generics ::object_rainbow::ReflessObject for #name #ty_generics #where_clause {}
688 };
689 TokenStream::from(output)
690}
691
692fn bounds_refless_object(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
693 let g = bounds_g(&generics);
694 match data {
695 Data::Struct(data) => {
696 let last_at = data.fields.len().checked_sub(1).unwrap_or_default();
697 for (i, f) in data.fields.iter().enumerate() {
698 let last = i == last_at;
699 let ty = &f.ty;
700 let tr = if last {
701 quote!(::object_rainbow::ReflessObject)
702 } else {
703 quote!(::object_rainbow::ReflessInline)
704 };
705 if type_contains_generics(&g, ty) {
706 generics.make_where_clause().predicates.push(
707 parse_quote_spanned! { ty.span() =>
708 #ty: #tr
709 },
710 );
711 }
712 }
713 }
714 Data::Enum(data) => {
715 for v in data.variants.iter() {
716 let last_at = v.fields.len().checked_sub(1).unwrap_or_default();
717 for (i, f) in v.fields.iter().enumerate() {
718 let last = i == last_at;
719 let ty = &f.ty;
720 let tr = if last {
721 quote!(::object_rainbow::ReflessObject)
722 } else {
723 quote!(::object_rainbow::ReflessInline)
724 };
725 if type_contains_generics(&g, ty) {
726 generics.make_where_clause().predicates.push(
727 parse_quote_spanned! { ty.span() =>
728 #ty: #tr
729 },
730 );
731 }
732 }
733 }
734 }
735 Data::Union(data) => {
736 return Err(Error::new_spanned(
737 data.union_token,
738 "`union`s are not supported",
739 ));
740 }
741 }
742 Ok(generics)
743}
744
745#[proc_macro_derive(ReflessInline)]
746pub fn derive_refless_inline(input: TokenStream) -> TokenStream {
747 let input = parse_macro_input!(input as DeriveInput);
748 let name = input.ident;
749 let generics = match bounds_refless_inline(input.generics, &input.data) {
750 Ok(g) => g,
751 Err(e) => return e.into_compile_error().into(),
752 };
753 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
754 let output = quote! {
755 impl #impl_generics ::object_rainbow::ReflessInline for #name #ty_generics #where_clause {}
756 };
757 TokenStream::from(output)
758}
759
760fn bounds_refless_inline(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
761 let g = bounds_g(&generics);
762 match data {
763 Data::Struct(data) => {
764 for f in data.fields.iter() {
765 let ty = &f.ty;
766 if type_contains_generics(&g, ty) {
767 generics.make_where_clause().predicates.push(
768 parse_quote_spanned! { ty.span() =>
769 #ty: ::object_rainbow::ReflessInline
770 },
771 );
772 }
773 }
774 }
775 Data::Enum(data) => {
776 for v in data.variants.iter() {
777 for f in v.fields.iter() {
778 let ty = &f.ty;
779 if type_contains_generics(&g, ty) {
780 generics.make_where_clause().predicates.push(
781 parse_quote_spanned! { ty.span() =>
782 #ty: ::object_rainbow::ReflessInline
783 },
784 );
785 }
786 }
787 }
788 }
789 Data::Union(data) => {
790 return Err(Error::new_spanned(
791 data.union_token,
792 "`union`s are not supported",
793 ));
794 }
795 }
796 Ok(generics)
797}
798
799#[proc_macro_derive(Size)]
800pub fn derive_size(input: TokenStream) -> TokenStream {
801 let input = parse_macro_input!(input as DeriveInput);
802 let name = input.ident;
803 let size_arr = gen_size_arr(&input.data);
804 let size = gen_size(&input.data);
805 let generics = match bounds_size(input.generics.clone(), &input.data, &size_arr) {
806 Ok(g) => g,
807 Err(e) => return e.into_compile_error().into(),
808 };
809 let (_, ty_generics, where_clause) = generics.split_for_impl();
810 let mut generics = input.generics;
811 generics.params.push(parse_quote!(
812 __Output: ::object_rainbow::typenum::Unsigned
813 ));
814 let (impl_generics, _, _) = generics.split_for_impl();
815 let output = quote! {
816 const _: () = {
817 use ::object_rainbow::typenum::tarr;
818
819 impl #impl_generics ::object_rainbow::Size for #name #ty_generics #where_clause {
820 const SIZE: usize = #size;
821
822 type Size = <#size_arr as ::object_rainbow::typenum::FoldAdd>::Output;
823 }
824 };
825 };
826 TokenStream::from(output)
827}
828
829fn bounds_size(
830 mut generics: Generics,
831 data: &Data,
832 size_arr: &proc_macro2::TokenStream,
833) -> syn::Result<Generics> {
834 let g = bounds_g(&generics);
835 match data {
836 Data::Struct(data) => {
837 for f in data.fields.iter() {
838 let ty = &f.ty;
839 if type_contains_generics(&g, ty) {
840 generics.make_where_clause().predicates.push(
841 parse_quote_spanned! { ty.span() =>
842 #ty: ::object_rainbow::Size
843 },
844 );
845 }
846 }
847 }
848 Data::Enum(data) => {
849 for v in data.variants.iter() {
850 for f in v.fields.iter() {
851 let ty = &f.ty;
852 if type_contains_generics(&g, ty) {
853 generics.make_where_clause().predicates.push(
854 parse_quote_spanned! { ty.span() =>
855 #ty: ::object_rainbow::Size
856 },
857 );
858 }
859 }
860 }
861 for v in data.variants.iter().skip(1) {
862 let arr = fields_size_arr(&v.fields, true);
863 generics.make_where_clause().predicates.push(parse_quote!(
864 #arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
865 ));
866 }
867 }
868 Data::Union(data) => {
869 return Err(Error::new_spanned(
870 data.union_token,
871 "`union`s are not supported",
872 ));
873 }
874 }
875 generics.make_where_clause().predicates.push(parse_quote!(
876 #size_arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
877 ));
878 Ok(generics)
879}
880
881fn fields_size_arr(fields: &syn::Fields, as_enum: bool) -> proc_macro2::TokenStream {
882 let kind_size = quote! {
883 <
884 <
885 <
886 Self
887 as
888 ::object_rainbow::Enum
889 >::Kind
890 as
891 ::object_rainbow::enumkind::EnumKind
892 >::Tag
893 as ::object_rainbow::Size
894 >::Size
895 };
896 if fields.is_empty() {
897 return if as_enum {
898 quote! { tarr![#kind_size, ::object_rainbow::typenum::consts::U0] }
899 } else {
900 quote! { tarr![::object_rainbow::typenum::consts::U0] }
901 };
902 }
903 let size_arr = fields.iter().map(|f| {
904 let ty = &f.ty;
905 quote! { <#ty as ::object_rainbow::Size>::Size }
906 });
907 if as_enum {
908 quote! { tarr![#kind_size, #(#size_arr),*] }
909 } else {
910 quote! { tarr![#(#size_arr),*] }
911 }
912}
913
914fn gen_size_arr(data: &Data) -> proc_macro2::TokenStream {
915 match data {
916 Data::Struct(data) => fields_size_arr(&data.fields, false),
917 Data::Enum(data) => {
918 if let Some(v) = data.variants.first() {
919 fields_size_arr(&v.fields, true)
920 } else {
921 Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
922 .into_compile_error()
923 }
924 }
925 Data::Union(data) => {
926 Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
927 }
928 }
929}
930
931fn fields_size(fields: &syn::Fields) -> proc_macro2::TokenStream {
932 if fields.is_empty() {
933 return quote! {0};
934 }
935 let size = fields.iter().map(|f| {
936 let ty = &f.ty;
937 quote! { <#ty as ::object_rainbow::Size>::SIZE }
938 });
939 quote! {
940 #(#size)+*
941 }
942}
943
944fn gen_size(data: &Data) -> proc_macro2::TokenStream {
945 match data {
946 Data::Struct(data) => fields_size(&data.fields),
947 Data::Enum(data) => {
948 if let Some(v) = data.variants.first() {
949 let size = fields_size(&v.fields);
950 let kind_size = quote! {
951 <
952 <
953 <
954 Self
955 as
956 ::object_rainbow::Enum
957 >::Kind
958 as
959 ::object_rainbow::enumkind::EnumKind
960 >::Tag
961 as ::object_rainbow::Size
962 >::SIZE
963 };
964 quote! { #kind_size + #size }
965 } else {
966 Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
967 .into_compile_error()
968 }
969 }
970 Data::Union(data) => {
971 Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
972 }
973 }
974}
975
976#[proc_macro_derive(Parse)]
977pub fn derive_parse(input: TokenStream) -> TokenStream {
978 let input = parse_macro_input!(input as DeriveInput);
979 let name = input.ident;
980 let generics = input.generics.clone();
981 let (_, ty_generics, _) = generics.split_for_impl();
982 let generics = match bounds_parse(input.generics, &input.data) {
983 Ok(g) => g,
984 Err(e) => return e.into_compile_error().into(),
985 };
986 let parse = gen_parse(&input.data);
987 let (impl_generics, _, where_clause) = generics.split_for_impl();
988 let output = quote! {
989 impl #impl_generics ::object_rainbow::Parse<__I> for #name #ty_generics #where_clause {
990 fn parse(mut input: __I) -> ::object_rainbow::Result<Self> {
991 #parse
992 }
993 }
994 };
995 TokenStream::from(output)
996}
997
998fn bounds_parse(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
999 match data {
1000 Data::Struct(data) => {
1001 let last_at = data.fields.len().checked_sub(1).unwrap_or_default();
1002 for (i, f) in data.fields.iter().enumerate() {
1003 let last = i == last_at;
1004 let ty = &f.ty;
1005 let tr = if last {
1006 quote!(::object_rainbow::Parse<__I>)
1007 } else {
1008 quote!(::object_rainbow::ParseInline<__I>)
1009 };
1010 generics
1011 .make_where_clause()
1012 .predicates
1013 .push(parse_quote_spanned! { ty.span() =>
1014 #ty: #tr
1015 });
1016 }
1017 }
1018 Data::Enum(data) => {
1019 for v in data.variants.iter() {
1020 let last_at = v.fields.len().checked_sub(1).unwrap_or_default();
1021 for (i, f) in v.fields.iter().enumerate() {
1022 let last = i == last_at;
1023 let ty = &f.ty;
1024 let tr = if last {
1025 quote!(::object_rainbow::Parse<__I>)
1026 } else {
1027 quote!(::object_rainbow::ParseInline<__I>)
1028 };
1029 generics.make_where_clause().predicates.push(
1030 parse_quote_spanned! { ty.span() =>
1031 #ty: #tr
1032 },
1033 );
1034 }
1035 }
1036 }
1037 Data::Union(data) => {
1038 return Err(Error::new_spanned(
1039 data.union_token,
1040 "`union`s are not supported",
1041 ));
1042 }
1043 }
1044 generics
1045 .params
1046 .push(parse_quote!(__I: ::object_rainbow::ParseInput));
1047 Ok(generics)
1048}
1049
1050fn gen_parse(data: &Data) -> proc_macro2::TokenStream {
1051 match data {
1052 Data::Struct(data) => {
1053 let arm = fields_parse(&data.fields);
1054 quote! { Ok(Self #arm)}
1055 }
1056 Data::Enum(data) => {
1057 let parse = data.variants.iter().map(|v| {
1058 let ident = &v.ident;
1059 let arm = fields_parse(&v.fields);
1060 quote! {
1061 <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
1062 }
1063 });
1064 quote! {
1065 Ok(match input.parse_inline()? {
1066 #(#parse)*
1067 })
1068 }
1069 }
1070 Data::Union(data) => {
1071 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1072 }
1073 }
1074}
1075
1076fn fields_parse(fields: &syn::Fields) -> proc_macro2::TokenStream {
1077 let last_at = fields.len().checked_sub(1).unwrap_or_default();
1078 match fields {
1079 syn::Fields::Named(fields) => {
1080 let parse = fields.named.iter().enumerate().map(|(i, f)| {
1081 let last = i == last_at;
1082 let i = f.ident.as_ref().unwrap();
1083 let method = if last {
1084 quote!(parse)
1085 } else {
1086 quote!(parse_inline)
1087 };
1088 quote_spanned! { f.ty.span() =>
1089 #i: input.#method()?
1090 }
1091 });
1092 quote! { { #(#parse),* } }
1093 }
1094 syn::Fields::Unnamed(fields) => {
1095 let parse = fields.unnamed.iter().enumerate().map(|(i, f)| {
1096 let last = i == last_at;
1097 let method = if last {
1098 quote!(parse)
1099 } else {
1100 quote!(parse_inline)
1101 };
1102 quote_spanned! { f.ty.span() =>
1103 input.#method()?
1104 }
1105 });
1106 quote! { (#(#parse),*) }
1107 }
1108 syn::Fields::Unit => quote! {},
1109 }
1110}
1111
1112#[proc_macro_derive(ParseInline)]
1113pub fn derive_parse_inline(input: TokenStream) -> TokenStream {
1114 let input = parse_macro_input!(input as DeriveInput);
1115 let name = input.ident;
1116 let generics = input.generics.clone();
1117 let (_, ty_generics, _) = generics.split_for_impl();
1118 let generics = match bounds_parse_inline(input.generics, &input.data) {
1119 Ok(g) => g,
1120 Err(e) => return e.into_compile_error().into(),
1121 };
1122 let parse_inline = gen_parse_inline(&input.data);
1123 let (impl_generics, _, where_clause) = generics.split_for_impl();
1124 let output = quote! {
1125 impl #impl_generics ::object_rainbow::ParseInline<__I> for #name #ty_generics #where_clause {
1126 fn parse_inline(input: &mut __I) -> ::object_rainbow::Result<Self> {
1127 #parse_inline
1128 }
1129 }
1130 };
1131 TokenStream::from(output)
1132}
1133
1134fn bounds_parse_inline(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
1135 match data {
1136 Data::Struct(data) => {
1137 for f in data.fields.iter() {
1138 let ty = &f.ty;
1139 generics
1140 .make_where_clause()
1141 .predicates
1142 .push(parse_quote_spanned! { ty.span() =>
1143 #ty: ::object_rainbow::ParseInline<__I>
1144 });
1145 }
1146 }
1147 Data::Enum(data) => {
1148 for v in data.variants.iter() {
1149 for f in v.fields.iter() {
1150 let ty = &f.ty;
1151 generics.make_where_clause().predicates.push(
1152 parse_quote_spanned! { ty.span() =>
1153 #ty: ::object_rainbow::ParseInline<__I>
1154 },
1155 );
1156 }
1157 }
1158 }
1159 Data::Union(data) => {
1160 return Err(Error::new_spanned(
1161 data.union_token,
1162 "`union`s are not supported",
1163 ));
1164 }
1165 }
1166 generics
1167 .params
1168 .push(parse_quote!(__I: ::object_rainbow::ParseInput));
1169 Ok(generics)
1170}
1171
1172fn fields_parse_inline(fields: &syn::Fields) -> proc_macro2::TokenStream {
1173 match fields {
1174 syn::Fields::Named(fields) => {
1175 let parse = fields.named.iter().map(|f| {
1176 let i = f.ident.as_ref().unwrap();
1177 quote_spanned! { f.ty.span() =>
1178 #i: input.parse_inline()?
1179 }
1180 });
1181 quote! { { #(#parse),* } }
1182 }
1183 syn::Fields::Unnamed(fields) => {
1184 let parse = fields.unnamed.iter().map(|f| {
1185 quote_spanned! { f.ty.span() =>
1186 input.parse_inline()?
1187 }
1188 });
1189 quote! { (#(#parse),*) }
1190 }
1191 syn::Fields::Unit => quote! {},
1192 }
1193}
1194
1195fn gen_parse_inline(data: &Data) -> proc_macro2::TokenStream {
1196 match data {
1197 Data::Struct(data) => {
1198 let arm = fields_parse_inline(&data.fields);
1199 quote! { Ok(Self #arm) }
1200 }
1201 Data::Enum(data) => {
1202 let parse_inline = data.variants.iter().map(|v| {
1203 let ident = &v.ident;
1204 let arm = fields_parse_inline(&v.fields);
1205 quote! {
1206 <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
1207 }
1208 });
1209 quote! {
1210 Ok(match input.parse_inline()? {
1211 #(#parse_inline)*
1212 })
1213 }
1214 }
1215 Data::Union(data) => {
1216 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1217 }
1218 }
1219}
1220
1221#[proc_macro_derive(ParseAsInline)]
1222pub fn derive_parse_as_inline(input: TokenStream) -> TokenStream {
1223 let input = parse_macro_input!(input as DeriveInput);
1224 let name = input.ident;
1225 let generics = input.generics.clone();
1226 let (_, ty_generics, _) = generics.split_for_impl();
1227 let generics = match bounds_parse_as_inline(input.generics, &name) {
1228 Ok(g) => g,
1229 Err(e) => return e.into_compile_error().into(),
1230 };
1231 let (impl_generics, _, where_clause) = generics.split_for_impl();
1232 let output = quote! {
1233 impl #impl_generics ::object_rainbow::Parse<__I> for #name #ty_generics #where_clause {
1234 fn parse(input: __I) -> ::object_rainbow::Result<Self> {
1235 ::object_rainbow::ParseInline::<__I>::parse_as_inline(input)
1236 }
1237 }
1238 };
1239 TokenStream::from(output)
1240}
1241
1242fn bounds_parse_as_inline(mut generics: Generics, name: &Ident) -> syn::Result<Generics> {
1243 generics
1244 .make_where_clause()
1245 .predicates
1246 .push(parse_quote_spanned! { name.span() =>
1247 Self: ::object_rainbow::ParseInline::<__I>
1248 });
1249 generics
1250 .params
1251 .push(parse_quote!(__I: ::object_rainbow::ParseInput));
1252 Ok(generics)
1253}
1254
1255fn parse_path(attr: &Attribute) -> syn::Result<Type> {
1256 attr.parse_args::<LitStr>()?.parse()
1257}
1258
1259fn attr_str(attr: &Attribute) -> Option<String> {
1260 Some(attr.path().get_ident()?.to_string())
1261}
1262
1263#[proc_macro_derive(Enum, attributes(enumtag))]
1264pub fn derive_enum(input: TokenStream) -> TokenStream {
1265 let input = parse_macro_input!(input as DeriveInput);
1266 let name = input.ident;
1267 let generics = input.generics.clone();
1268 let (_, ty_generics, _) = generics.split_for_impl();
1269 let generics = input.generics;
1270 let variants = gen_variants(&input.data);
1271 let variant_count = gen_variant_count(&input.data);
1272 let to_tag = gen_to_tag(&input.data);
1273 let from_tag = gen_from_tag(&input.data);
1274 let kind = gen_kind(&input.data);
1275 let (impl_generics, _, where_clause) = generics.split_for_impl();
1276 let mut errors = Vec::new();
1277 let mut enumtag = None;
1278 for attr in &input.attrs {
1279 if attr_str(attr).as_deref() == Some("enumtag") {
1280 match parse_path(attr) {
1281 Ok(path) => {
1282 if enumtag.is_some() {
1283 errors.push(Error::new_spanned(path, "duplicate tag"));
1284 } else {
1285 enumtag = Some(path);
1286 }
1287 }
1288 Err(e) => errors.push(e),
1289 }
1290 }
1291 }
1292 let enumtag = enumtag
1293 .unwrap_or_else(|| parse_quote!(::object_rainbow::numeric::Le<::core::num::NonZero<u8>>));
1294 let errors = errors.into_iter().map(|e| e.into_compile_error());
1295 let output = quote! {
1296 const _: () = {
1297 #(#errors)*
1298
1299 use ::object_rainbow::enumkind::EnumKind;
1300
1301 #[derive(Clone, Copy, ::object_rainbow::ParseAsInline)]
1302 enum __Kind {
1303 #variants
1304 }
1305
1306 impl ::object_rainbow::enumkind::EnumKind for __Kind {
1307 type Tag = ::object_rainbow::enumkind::EnumTag<
1308 #enumtag,
1309 #variant_count,
1310 >;
1311
1312 fn to_tag(self) -> Self::Tag {
1313 #to_tag
1314 }
1315
1316 fn from_tag(tag: Self::Tag) -> Self {
1317 #from_tag
1318 }
1319 }
1320
1321 impl<I: ::object_rainbow::ParseInput> ::object_rainbow::ParseInline<I> for __Kind {
1322 fn parse_inline(input: &mut I) -> ::object_rainbow::Result<Self> {
1323 Ok(::object_rainbow::enumkind::EnumKind::from_tag(input.parse_inline()?))
1324 }
1325 }
1326
1327 impl #impl_generics ::object_rainbow::Enum for #name #ty_generics #where_clause {
1328 type Kind = __Kind;
1329
1330 fn kind(&self) -> Self::Kind {
1331 #kind
1332 }
1333 }
1334 };
1335 };
1336 TokenStream::from(output)
1337}
1338
1339fn gen_variants(data: &Data) -> proc_macro2::TokenStream {
1340 match data {
1341 Data::Struct(data) => {
1342 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1343 }
1344 Data::Enum(data) => {
1345 let variants = data.variants.iter().map(|v| &v.ident);
1346 quote! { #(#variants),* }
1347 }
1348 Data::Union(data) => {
1349 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1350 }
1351 }
1352}
1353
1354fn gen_variant_count(data: &Data) -> proc_macro2::TokenStream {
1355 match data {
1356 Data::Struct(data) => {
1357 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1358 }
1359 Data::Enum(data) => {
1360 let variant_count = data.variants.len();
1361 quote! { #variant_count }
1362 }
1363 Data::Union(data) => {
1364 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1365 }
1366 }
1367}
1368
1369fn gen_to_tag(data: &Data) -> proc_macro2::TokenStream {
1370 match data {
1371 Data::Struct(data) => {
1372 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1373 }
1374 Data::Enum(data) => {
1375 let to_tag = data.variants.iter().enumerate().map(|(i, v)| {
1376 let ident = &v.ident;
1377 quote_spanned! { ident.span() =>
1378 Self::#ident => ::object_rainbow::enumkind::EnumTag::from_const::<#i>(),
1379 }
1380 });
1381 quote! {
1382 match self {
1383 #(#to_tag)*
1384 }
1385 }
1386 }
1387 Data::Union(data) => {
1388 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1389 }
1390 }
1391}
1392
1393fn gen_from_tag(data: &Data) -> proc_macro2::TokenStream {
1394 match data {
1395 Data::Struct(data) => {
1396 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1397 }
1398 Data::Enum(data) => {
1399 let from_tag = data.variants.iter().enumerate().map(|(i, v)| {
1400 let ident = &v.ident;
1401 quote_spanned! { ident.span() =>
1402 #i => Self::#ident,
1403 }
1404 });
1405 quote! {
1406 match tag.to_usize() {
1407 #(#from_tag)*
1408 _ => unreachable!(),
1409 }
1410 }
1411 }
1412 Data::Union(data) => {
1413 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1414 }
1415 }
1416}
1417
1418fn gen_kind(data: &Data) -> proc_macro2::TokenStream {
1419 match data {
1420 Data::Struct(data) => {
1421 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1422 }
1423 Data::Enum(data) => {
1424 let variants = data.variants.iter().map(|v| {
1425 let ident = &v.ident;
1426 quote_spanned! { ident.span() =>
1427 Self::#ident {..} => __Kind::#ident,
1428 }
1429 });
1430 quote! {
1431 match self {
1432 #(#variants)*
1433 }
1434 }
1435 }
1436 Data::Union(data) => {
1437 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1438 }
1439 }
1440}
1441
1442#[proc_macro_derive(MaybeHasNiche)]
1443pub fn derive_maybe_has_niche(input: TokenStream) -> TokenStream {
1444 let input = parse_macro_input!(input as DeriveInput);
1445 let name = input.ident;
1446 let mn_array = gen_mn_array(&input.data);
1447 let (_, ty_generics, _) = input.generics.split_for_impl();
1448 let generics = match bounds_maybe_has_niche(input.generics.clone(), &input.data) {
1449 Ok(g) => g,
1450 Err(e) => return e.into_compile_error().into(),
1451 };
1452 let (impl_generics, _, where_clause) = generics.split_for_impl();
1453 let output = quote! {
1454 const _: () = {
1455 use ::object_rainbow::typenum::tarr;
1456
1457 impl #impl_generics ::object_rainbow::MaybeHasNiche for #name #ty_generics #where_clause {
1458 type MnArray = #mn_array;
1459 }
1460 };
1461 };
1462 TokenStream::from(output)
1463}
1464
1465fn bounds_maybe_has_niche(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
1466 match data {
1467 Data::Struct(data) => {
1468 for f in data.fields.iter() {
1469 let ty = &f.ty;
1470 generics
1471 .make_where_clause()
1472 .predicates
1473 .push(parse_quote_spanned! { ty.span() =>
1474 #ty: ::object_rainbow::MaybeHasNiche<
1475 MnArray: ::object_rainbow::MnArray<
1476 MaybeNiche: ::object_rainbow::MaybeNiche
1477 >
1478 >
1479 });
1480 }
1481 }
1482 Data::Enum(data) => {
1483 generics.params.push(parse_quote!(
1484 __N: ::object_rainbow::typenum::Unsigned
1485 ));
1486 for (i, v) in data.variants.iter().enumerate() {
1487 let mn_array = fields_mn_array(&v.fields, Some(i));
1488 generics
1489 .make_where_clause()
1490 .predicates
1491 .push(parse_quote_spanned! { v.span() =>
1492 #mn_array: ::object_rainbow::MnArray<
1493 MaybeNiche: ::object_rainbow::NicheOr<N = __N>
1494 >
1495 });
1496 for f in v.fields.iter() {
1497 let ty = &f.ty;
1498 generics.make_where_clause().predicates.push(
1499 parse_quote_spanned! { ty.span() =>
1500 #ty: ::object_rainbow::MaybeHasNiche<
1501 MnArray: ::object_rainbow::MnArray<
1502 MaybeNiche: ::object_rainbow::MaybeNiche
1503 >
1504 >
1505 },
1506 );
1507 }
1508 }
1509 }
1510 Data::Union(data) => {
1511 return Err(Error::new_spanned(
1512 data.union_token,
1513 "`union`s are not supported",
1514 ));
1515 }
1516 }
1517 Ok(generics)
1518}
1519
1520fn fields_mn_array(fields: &syn::Fields, variant: Option<usize>) -> proc_macro2::TokenStream {
1521 let mn_array = fields.iter().map(|f| {
1522 let ty = &f.ty;
1523 quote! {
1524 <
1525 <
1526 #ty
1527 as
1528 ::object_rainbow::MaybeHasNiche
1529 >::MnArray
1530 as
1531 ::object_rainbow::MnArray
1532 >::MaybeNiche
1533 }
1534 });
1535 if let Some(variant) = variant {
1536 let kind_niche = quote! {
1537 ::object_rainbow::AutoEnumNiche<Self, #variant>
1538 };
1539 quote! { tarr![#kind_niche, ::object_rainbow::NoNiche<::object_rainbow::HackNiche<#variant>>, #(#mn_array),*] }
1540 } else {
1541 quote! { tarr![#(#mn_array),*] }
1542 }
1543}
1544
1545fn gen_mn_array(data: &Data) -> proc_macro2::TokenStream {
1546 match data {
1547 Data::Struct(data) => fields_mn_array(&data.fields, None),
1548 Data::Enum(data) => {
1549 let mn_array = data.variants.iter().enumerate().map(|(i, v)| {
1550 let mn_array = fields_mn_array(&v.fields, Some(i));
1551 quote! { <#mn_array as ::object_rainbow::MnArray>::MaybeNiche }
1552 });
1553 quote! {
1554 ::object_rainbow::NicheFoldOrArray<tarr![#(#mn_array),*]>
1555 }
1556 }
1557 Data::Union(data) => {
1558 Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1559 }
1560 }
1561}