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