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