1use std::collections::BTreeSet;
2
3use darling::FromMeta;
4use proc_macro::TokenStream;
5use quote::{ToTokens, quote, quote_spanned};
6use syn::{
7 Attribute, Data, DeriveInput, Error, Expr, Field, GenericParam, Generics, Ident, LitStr, Path,
8 Type, TypeGenerics, parse::Parse, parse_macro_input, parse_quote, parse_quote_spanned,
9 spanned::Spanned, token::Comma,
10};
11
12use self::contains_generics::{GContext, type_contains_generics};
13
14mod contains_generics;
15
16fn bounds_g(generics: &Generics) -> BTreeSet<Ident> {
17 generics
18 .params
19 .iter()
20 .filter_map(|param| match param {
21 GenericParam::Lifetime(_) => None,
22 GenericParam::Type(param) => Some(¶m.ident),
23 GenericParam::Const(param) => Some(¶m.ident),
24 })
25 .cloned()
26 .collect()
27}
28
29#[derive(Debug, FromMeta)]
30#[darling(derive_syn_parse)]
31struct RainbowArgs {
32 #[darling(default)]
33 remote: Option<Type>,
34}
35
36fn parse_for(name: &Ident, attrs: &[Attribute]) -> proc_macro2::TokenStream {
37 for attr in attrs {
38 if attr_str(attr).as_deref() == Some("rainbow") {
39 match attr.parse_args::<RainbowArgs>() {
40 Ok(RainbowArgs { remote }) => {
41 if let Some(remote) = remote {
42 return remote.to_token_stream();
43 }
44 }
45 Err(e) => return e.into_compile_error(),
46 }
47 }
48 }
49 name.to_token_stream()
50}
51
52#[proc_macro_derive(ToOutput, attributes(rainbow))]
53pub fn derive_to_output(input: TokenStream) -> TokenStream {
54 let input = parse_macro_input!(input as DeriveInput);
55 let name = input.ident;
56 let generics = match bounds_to_output(input.generics, &input.data) {
57 Ok(g) => g,
58 Err(e) => return e.into_compile_error().into(),
59 };
60 let to_output = gen_to_output(&input.data);
61 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
62 let target = parse_for(&name, &input.attrs);
63 let output = quote! {
64 #[automatically_derived]
65 impl #impl_generics ::object_rainbow::ToOutput for #target #ty_generics #where_clause {
66 fn to_output(&self, output: &mut dyn ::object_rainbow::Output) {
67 #to_output
68 }
69 }
70 };
71 TokenStream::from(output)
72}
73
74fn bounds_to_output(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
75 let g = &bounds_g(&generics);
76 match data {
77 Data::Struct(data) => {
78 let last_at = data.fields.len().checked_sub(1).unwrap_or_default();
79 for (i, f) in data.fields.iter().enumerate() {
80 let last = i == last_at;
81 let ty = &f.ty;
82 let tr = if last {
83 quote!(::object_rainbow::ToOutput)
84 } else {
85 quote!(::object_rainbow::InlineOutput)
86 };
87 if !last || type_contains_generics(GContext { g, always: false }, ty) {
88 generics.make_where_clause().predicates.push(
89 parse_quote_spanned! { ty.span() =>
90 #ty: #tr
91 },
92 );
93 }
94 }
95 }
96 Data::Enum(data) => {
97 for v in data.variants.iter() {
98 let last_at = v.fields.len().checked_sub(1).unwrap_or_default();
99 for (i, f) in v.fields.iter().enumerate() {
100 let last = i == last_at;
101 let ty = &f.ty;
102 let tr = if last {
103 quote!(::object_rainbow::ToOutput)
104 } else {
105 quote!(::object_rainbow::InlineOutput)
106 };
107 if !last || type_contains_generics(GContext { g, always: false }, ty) {
108 generics.make_where_clause().predicates.push(
109 parse_quote_spanned! { ty.span() =>
110 #ty: #tr
111 },
112 );
113 }
114 }
115 }
116 }
117 Data::Union(data) => {
118 return Err(Error::new_spanned(
119 data.union_token,
120 "`union`s are not supported",
121 ));
122 }
123 }
124 Ok(generics)
125}
126
127fn fields_to_output(fields: &syn::Fields) -> proc_macro2::TokenStream {
128 match fields {
129 syn::Fields::Named(fields) => {
130 let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
131 let to_output = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
132 quote_spanned! { f.ty.span() =>
133 #i.to_output(output)
134 }
135 });
136 quote! {
137 { #(#let_self),* } => {
138 #(#to_output);*
139 }
140 }
141 }
142 syn::Fields::Unnamed(fields) => {
143 let let_self = fields
144 .unnamed
145 .iter()
146 .enumerate()
147 .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
148 let to_output = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
149 quote_spanned! { f.ty.span() =>
150 #i.to_output(output)
151 }
152 });
153 quote! {
154 (#(#let_self),*) => {
155 #(#to_output);*
156 }
157 }
158 }
159 syn::Fields::Unit => quote! {
160 => {}
161 },
162 }
163}
164
165fn gen_to_output(data: &Data) -> proc_macro2::TokenStream {
166 match data {
167 Data::Struct(data) => {
168 let arm = fields_to_output(&data.fields);
169 quote! {
170 match self {
171 Self #arm
172 }
173 }
174 }
175 Data::Enum(data) => {
176 let to_output = data.variants.iter().map(|v| {
177 let ident = &v.ident;
178 let arm = fields_to_output(&v.fields);
179 quote! { Self::#ident #arm }
180 });
181 quote! {
182 let kind = ::object_rainbow::Enum::kind(self);
183 let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
184 tag.to_output(output);
185 match self {
186 #(#to_output)*
187 }
188 }
189 }
190 Data::Union(data) => {
191 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
192 }
193 }
194}
195
196#[proc_macro_derive(InlineOutput)]
197pub fn derive_inline_output(input: TokenStream) -> TokenStream {
198 let input = parse_macro_input!(input as DeriveInput);
199 let name = input.ident;
200 let generics = match bounds_inline_output(input.generics, &input.data) {
201 Ok(g) => g,
202 Err(e) => return e.into_compile_error().into(),
203 };
204 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
205 let target = parse_for(&name, &input.attrs);
206 let output = quote! {
207 #[automatically_derived]
208 impl #impl_generics ::object_rainbow::InlineOutput for #target #ty_generics #where_clause {}
209 };
210 TokenStream::from(output)
211}
212
213fn bounds_inline_output(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
214 match data {
215 Data::Struct(data) => {
216 for f in data.fields.iter() {
217 let ty = &f.ty;
218 generics
219 .make_where_clause()
220 .predicates
221 .push(parse_quote_spanned! { ty.span() =>
222 #ty: ::object_rainbow::InlineOutput
223 });
224 }
225 }
226 Data::Enum(data) => {
227 for v in data.variants.iter() {
228 for f in v.fields.iter() {
229 let ty = &f.ty;
230 generics.make_where_clause().predicates.push(
231 parse_quote_spanned! { ty.span() =>
232 #ty: ::object_rainbow::InlineOutput
233 },
234 );
235 }
236 }
237 }
238 Data::Union(data) => {
239 return Err(Error::new_spanned(
240 data.union_token,
241 "`union`s are not supported",
242 ));
243 }
244 }
245 Ok(generics)
246}
247
248#[proc_macro_derive(ListHashes, attributes(topology))]
249pub fn derive_list_hashes(input: TokenStream) -> TokenStream {
250 let input = parse_macro_input!(input as DeriveInput);
251 let name = input.ident;
252 let generics = input.generics.clone();
253 let (_, ty_generics, _) = generics.split_for_impl();
254 let generics = match bounds_list_hashes(input.generics, &input.data) {
255 Ok(g) => g,
256 Err(e) => return e.into_compile_error().into(),
257 };
258 let list_hashes = gen_list_hashes(&input.data);
259 let (impl_generics, _, where_clause) = generics.split_for_impl();
260 let target = parse_for(&name, &input.attrs);
261 let output = quote! {
262 #[automatically_derived]
263 impl #impl_generics ::object_rainbow::ListHashes for #target #ty_generics #where_clause {
264 fn list_hashes(&self, visitor: &mut impl FnMut(::object_rainbow::Hash)) {
265 #list_hashes
266 }
267 }
268 };
269 TokenStream::from(output)
270}
271
272fn bounds_list_hashes(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
273 let g = &bounds_g(&generics);
274 match data {
275 Data::Struct(data) => {
276 for f in data.fields.iter() {
277 let ty = &f.ty;
278 if type_contains_generics(GContext { g, always: false }, ty) {
279 generics.make_where_clause().predicates.push(
280 parse_quote_spanned! { ty.span() =>
281 #ty: ::object_rainbow::ListHashes
282 },
283 );
284 }
285 }
286 }
287 Data::Enum(data) => {
288 for v in data.variants.iter() {
289 for f in v.fields.iter() {
290 let ty = &f.ty;
291 if type_contains_generics(GContext { g, always: false }, ty) {
292 generics.make_where_clause().predicates.push(
293 parse_quote_spanned! { ty.span() =>
294 #ty: ::object_rainbow::ListHashes
295 },
296 );
297 }
298 }
299 }
300 }
301 Data::Union(data) => {
302 return Err(Error::new_spanned(
303 data.union_token,
304 "`union`s are not supported",
305 ));
306 }
307 }
308 Ok(generics)
309}
310
311fn fields_list_hashes(fields: &syn::Fields) -> proc_macro2::TokenStream {
312 match fields {
313 syn::Fields::Named(fields) => {
314 let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
315 let list_hashes = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
316 quote_spanned! { f.ty.span() =>
317 #i.list_hashes(visitor)
318 }
319 });
320 quote! {
321 { #(#let_self),* } => {
322 #(#list_hashes);*
323 }
324 }
325 }
326 syn::Fields::Unnamed(fields) => {
327 let let_self = fields
328 .unnamed
329 .iter()
330 .enumerate()
331 .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
332 let list_hashes = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
333 quote_spanned! { f.ty.span() =>
334 #i.list_hashes(visitor)
335 }
336 });
337 quote! {
338 (#(#let_self),*) => {
339 #(#list_hashes);*
340 }
341 }
342 }
343 syn::Fields::Unit => quote! {
344 => {}
345 },
346 }
347}
348
349fn gen_list_hashes(data: &Data) -> proc_macro2::TokenStream {
350 match data {
351 Data::Struct(data) => {
352 let arm = fields_list_hashes(&data.fields);
353 quote! {
354 match self {
355 Self #arm
356 }
357 }
358 }
359 Data::Enum(data) => {
360 let to_output = data.variants.iter().map(|v| {
361 let ident = &v.ident;
362 let arm = fields_list_hashes(&v.fields);
363 quote! { Self::#ident #arm }
364 });
365 quote! {
366 let kind = ::object_rainbow::Enum::kind(self);
367 let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
368 tag.list_hashes(visitor);
369 match self {
370 #(#to_output)*
371 }
372 }
373 }
374 Data::Union(data) => {
375 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
376 }
377 }
378}
379
380#[proc_macro_derive(Topological, attributes(topology))]
381pub fn derive_topological(input: TokenStream) -> TokenStream {
382 let input = parse_macro_input!(input as DeriveInput);
383 let name = input.ident;
384 let generics = input.generics.clone();
385 let (_, ty_generics, _) = generics.split_for_impl();
386 let mut defs = Vec::new();
387 let generics =
388 match bounds_topological(input.generics, &input.data, &input.attrs, &name, &mut defs) {
389 Ok(g) => g,
390 Err(e) => return e.into_compile_error().into(),
391 };
392 let traverse = gen_traverse(&input.data, &ty_generics);
393 let (impl_generics, _, where_clause) = generics.split_for_impl();
394 let target = parse_for(&name, &input.attrs);
395 let output = quote! {
396 const _: () = {
397 #(#defs)*
398
399 #[automatically_derived]
400 impl #impl_generics ::object_rainbow::Topological for #target #ty_generics
401 #where_clause
402 {
403 fn traverse(&self, visitor: &mut impl ::object_rainbow::PointVisitor) {
404 #traverse
405 }
406 }
407 };
408 };
409 TokenStream::from(output)
410}
411
412#[derive(Debug, FromMeta)]
413#[darling(derive_syn_parse)]
414struct ContainerTopologyArgs {
415 #[darling(default)]
416 recursive: bool,
417 #[darling(default)]
418 inline: bool,
419}
420
421fn parse_recursive_inline(attrs: &[Attribute]) -> syn::Result<(bool, bool)> {
422 let mut r = false;
423 let mut i = false;
424 for attr in attrs {
425 if attr_str(attr).as_deref() == Some("topology") {
426 let ContainerTopologyArgs { recursive, inline } = attr.parse_args()?;
427 if recursive {
428 r = true;
429 }
430 if inline {
431 i = true;
432 }
433 }
434 }
435 Ok((r, i))
436}
437
438#[derive(Debug, FromMeta)]
439#[darling(derive_syn_parse)]
440struct FieldTopologyArgs {
441 bound: Option<Path>,
442 #[darling(default)]
443 unchecked: bool,
444 with: Option<Expr>,
445 #[darling(default, rename = "unstable_mutual")]
446 mutual: bool,
447}
448
449fn bounds_topological(
450 mut generics: Generics,
451 data: &Data,
452 attrs: &[Attribute],
453 name: &Ident,
454 defs: &mut Vec<proc_macro2::TokenStream>,
455) -> syn::Result<Generics> {
456 let (recursive, inline) = parse_recursive_inline(attrs)?;
457 let g = &bounds_g(&generics);
458 let g_clone = generics.clone();
459 let (impl_generics, ty_generics, where_clause) = g_clone.split_for_impl();
460 let this = quote_spanned! { name.span() =>
461 #name #ty_generics
462 };
463 let bound = if recursive {
464 quote! { ::object_rainbow::Traversible }
465 } else {
466 quote! { ::object_rainbow::Topological }
467 };
468 match data {
469 Data::Struct(data) => {
470 'field: for f in data.fields.iter() {
471 let ty = &f.ty;
472 let mut b = None;
473 for attr in &f.attrs {
474 if attr_str(attr).as_deref() == Some("topology") {
475 let FieldTopologyArgs {
476 bound,
477 unchecked,
478 mutual,
479 ..
480 } = attr.parse_args()?;
481 if mutual {
482 let conditional =
483 format!("__ConditionalTopology_{}", f.ident.as_ref().unwrap());
484 let conditional = Ident::new(&conditional, f.span());
485 defs.push(quote! {
486 #[allow(non_camel_case_types)]
487 trait #conditional #impl_generics #where_clause {
488 fn traverse(
489 &self, visitor: &mut impl ::object_rainbow::PointVisitor,
490 ) where #this: ::object_rainbow::Traversible;
491 }
492
493 impl #impl_generics #conditional #ty_generics for #ty #where_clause {
494 fn traverse(
495 &self, visitor: &mut impl ::object_rainbow::PointVisitor,
496 ) where #this: ::object_rainbow::Traversible {
497 ::object_rainbow::Topological::traverse(self, visitor)
498 }
499 }
500 });
501 b = Some(parse_quote!(#conditional #ty_generics));
502 }
503 if unchecked {
504 continue 'field;
505 }
506 if let Some(bound) = bound {
507 b = Some(bound);
508 }
509 }
510 }
511 let bound = if let Some(bound) = b {
512 quote! { #bound }
513 } else {
514 bound.clone()
515 };
516 if type_contains_generics(GContext { g, always: false }, ty) {
517 generics.make_where_clause().predicates.push(
518 parse_quote_spanned! { ty.span() =>
519 #ty: #bound
520 },
521 );
522 }
523 }
524 }
525 Data::Enum(data) => {
526 for v in data.variants.iter() {
527 'field: for (i, f) in v.fields.iter().enumerate() {
528 let ty = &f.ty;
529 let mut b = None;
530 for attr in &f.attrs {
531 if attr_str(attr).as_deref() == Some("topology") {
532 let FieldTopologyArgs {
533 bound,
534 unchecked,
535 mutual,
536 ..
537 } = attr.parse_args()?;
538 if mutual {
539 let conditional = format!("__ConditionalTopology_{i}");
540 let conditional = Ident::new(&conditional, f.span());
541 defs.push(quote! {
542 #[allow(non_camel_case_types)]
543 trait #conditional #impl_generics #where_clause {
544 fn traverse(
545 &self, visitor: &mut impl ::object_rainbow::PointVisitor,
546 ) where #this: ::object_rainbow::Traversible;
547 }
548
549 impl #impl_generics #conditional #ty_generics for #ty #where_clause {
550 fn traverse(
551 &self, visitor: &mut impl ::object_rainbow::PointVisitor,
552 ) where #this: ::object_rainbow::Traversible {
553 ::object_rainbow::Topological::traverse(self, visitor)
554 }
555 }
556 });
557 }
558 if unchecked {
559 continue 'field;
560 }
561 if let Some(bound) = bound {
562 b = Some(bound);
563 }
564 }
565 }
566 let bound = if let Some(bound) = b {
567 quote! { #bound }
568 } else {
569 bound.clone()
570 };
571 if type_contains_generics(GContext { g, always: false }, ty) {
572 generics.make_where_clause().predicates.push(
573 parse_quote_spanned! { ty.span() =>
574 #ty: #bound
575 },
576 );
577 }
578 }
579 }
580 }
581 Data::Union(data) => {
582 return Err(Error::new_spanned(
583 data.union_token,
584 "`union`s are not supported",
585 ));
586 }
587 }
588 let output_bound = if inline {
589 quote! {
590 ::object_rainbow::InlineOutput
591 }
592 } else {
593 quote! {
594 ::object_rainbow::ToOutput
595 }
596 };
597 if recursive {
598 generics
599 .make_where_clause()
600 .predicates
601 .push(parse_quote_spanned! { name.span() =>
602 Self: #output_bound + ::object_rainbow::Tagged
603 });
604 }
605 Ok(generics)
606}
607
608fn fields_traverse(
609 fields: &syn::Fields,
610 ty_generics: &TypeGenerics<'_>,
611) -> proc_macro2::TokenStream {
612 match fields {
613 syn::Fields::Named(fields) => {
614 let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
615 let traverse = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
616 let ty = &f.ty;
617 let mut w = None;
618 let mut b = None;
619 for attr in &f.attrs {
620 if attr_str(attr).as_deref() == Some("topology") {
621 let FieldTopologyArgs {
622 with,
623 bound,
624 mutual,
625 ..
626 } = match attr.parse_args() {
627 Ok(args) => args,
628 Err(e) => return e.into_compile_error(),
629 };
630 if mutual {
631 let conditional = format!("__ConditionalTopology_{i}");
632 let conditional = Ident::new(&conditional, f.span());
633 w = Some(parse_quote!(traverse));
634 b = Some(parse_quote!(#conditional #ty_generics));
635 }
636 if let Some(with) = with {
637 w = Some(with);
638 }
639 if let Some(bound) = bound {
640 b = Some(bound);
641 }
642 }
643 }
644 if let Some(with) = w {
645 if let Some(bound) = b {
646 quote_spanned! { f.ty.span() =>
647 <#ty as #bound>::#with(#i, visitor)
648 }
649 } else {
650 quote_spanned! { f.ty.span() =>
651 #with(#i, visitor)
652 }
653 }
654 } else {
655 quote_spanned! { f.ty.span() =>
656 #i.traverse(visitor)
657 }
658 }
659 });
660 quote! {
661 { #(#let_self),* } => {
662 #(#traverse);*
663 }
664 }
665 }
666 syn::Fields::Unnamed(fields) => {
667 let let_self = fields
668 .unnamed
669 .iter()
670 .enumerate()
671 .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
672 let traverse = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
673 let ty = &f.ty;
674 let mut w = None;
675 let mut b = None;
676 for attr in &f.attrs {
677 if attr_str(attr).as_deref() == Some("topology") {
678 let FieldTopologyArgs {
679 with,
680 bound,
681 mutual,
682 ..
683 } = match attr.parse_args() {
684 Ok(args) => args,
685 Err(e) => return e.into_compile_error(),
686 };
687 if mutual {
688 let conditional = format!("__ConditionalTopology_{i}");
689 let conditional = Ident::new(&conditional, f.span());
690 w = Some(parse_quote!(traverse));
691 b = Some(parse_quote!(#conditional #ty_generics));
692 }
693 if let Some(with) = with {
694 w = Some(with);
695 }
696 if let Some(bound) = bound {
697 b = Some(bound);
698 }
699 }
700 }
701 if let Some(with) = w {
702 if let Some(bound) = b {
703 quote_spanned! { f.ty.span() =>
704 <#ty as #bound>::#with(#i, visitor)
705 }
706 } else {
707 quote_spanned! { f.ty.span() =>
708 #with(#i, visitor)
709 }
710 }
711 } else {
712 quote_spanned! { f.ty.span() =>
713 #i.traverse(visitor)
714 }
715 }
716 });
717 quote! {
718 (#(#let_self),*) => {
719 #(#traverse);*
720 }
721 }
722 }
723 syn::Fields::Unit => quote! {
724 => {}
725 },
726 }
727}
728
729fn gen_traverse(data: &Data, ty_generics: &TypeGenerics<'_>) -> proc_macro2::TokenStream {
730 match data {
731 Data::Struct(data) => {
732 let arm = fields_traverse(&data.fields, ty_generics);
733 quote! {
734 match self {
735 Self #arm
736 }
737 }
738 }
739 Data::Enum(data) => {
740 let to_output = data.variants.iter().map(|v| {
741 let ident = &v.ident;
742 let arm = fields_traverse(&v.fields, ty_generics);
743 quote! { Self::#ident #arm }
744 });
745 quote! {
746 let kind = ::object_rainbow::Enum::kind(self);
747 let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
748 tag.traverse(visitor);
749 match self {
750 #(#to_output)*
751 }
752 }
753 }
754 Data::Union(data) => {
755 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
756 }
757 }
758}
759
760#[proc_macro_derive(Tagged, attributes(tags))]
761pub fn derive_tagged(input: TokenStream) -> TokenStream {
762 let input = parse_macro_input!(input as DeriveInput);
763 let name = input.ident;
764 let mut errors = Vec::new();
765 let generics = match bounds_tagged(input.generics, &input.data, &mut errors) {
766 Ok(g) => g,
767 Err(e) => return e.into_compile_error().into(),
768 };
769 let tags = gen_tags(&input.data, &input.attrs, &mut errors);
770 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
771 let errors = errors.into_iter().map(|e| e.into_compile_error());
772 let target = parse_for(&name, &input.attrs);
773 let output = quote! {
774 #(#errors)*
775
776 #[automatically_derived]
777 impl #impl_generics ::object_rainbow::Tagged for #target #ty_generics #where_clause {
778 const TAGS: ::object_rainbow::Tags = #tags;
779 }
780 };
781 TokenStream::from(output)
782}
783
784struct FieldTagArgs {
785 skip: bool,
786}
787
788impl Parse for FieldTagArgs {
789 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
790 let mut skip = false;
791 while !input.is_empty() {
792 let ident = input.parse::<Ident>()?;
793 if ident.to_string().as_str() != "skip" {
794 return Err(Error::new(ident.span(), "expected: skip"));
795 }
796 skip = true;
797 if !input.is_empty() {
798 input.parse::<Comma>()?;
799 }
800 }
801 Ok(Self { skip })
802 }
803}
804
805fn bounds_tagged(
806 mut generics: Generics,
807 data: &Data,
808 errors: &mut Vec<Error>,
809) -> syn::Result<Generics> {
810 let g = &bounds_g(&generics);
811 match data {
812 Data::Struct(data) => {
813 for f in data.fields.iter() {
814 let mut skip = false;
815 for attr in &f.attrs {
816 if attr_str(attr).as_deref() == Some("tags") {
817 match attr.parse_args::<FieldTagArgs>() {
818 Ok(args) => skip |= args.skip,
819 Err(e) => errors.push(e),
820 }
821 }
822 }
823 if !skip {
824 let ty = &f.ty;
825 if type_contains_generics(GContext { g, always: false }, ty) {
826 generics.make_where_clause().predicates.push(
827 parse_quote_spanned! { ty.span() =>
828 #ty: ::object_rainbow::Tagged
829 },
830 );
831 }
832 }
833 }
834 }
835 Data::Enum(data) => {
836 for v in data.variants.iter() {
837 for f in v.fields.iter() {
838 let mut skip = false;
839 for attr in &f.attrs {
840 if attr_str(attr).as_deref() == Some("tags") {
841 match attr.parse_args::<FieldTagArgs>() {
842 Ok(args) => skip |= args.skip,
843 Err(e) => errors.push(e),
844 }
845 }
846 }
847 if !skip {
848 let ty = &f.ty;
849 if type_contains_generics(GContext { g, always: false }, ty) {
850 generics.make_where_clause().predicates.push(
851 parse_quote_spanned! { ty.span() =>
852 #ty: ::object_rainbow::Tagged
853 },
854 );
855 }
856 }
857 }
858 }
859 }
860 Data::Union(data) => {
861 return Err(Error::new_spanned(
862 data.union_token,
863 "`union`s are not supported",
864 ));
865 }
866 }
867 Ok(generics)
868}
869
870struct StructTagArgs {
871 tags: Vec<LitStr>,
872}
873
874impl Parse for StructTagArgs {
875 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
876 let mut tags = Vec::new();
877 while !input.is_empty() {
878 let tag = input.parse::<LitStr>()?;
879 tags.push(tag);
880 if !input.is_empty() {
881 input.parse::<Comma>()?;
882 }
883 }
884 Ok(Self { tags })
885 }
886}
887
888fn fields_tags(fields: &syn::Fields) -> Vec<proc_macro2::TokenStream> {
889 fields
890 .iter()
891 .filter_map(|f| {
892 let mut skip = false;
893 for attr in &f.attrs {
894 if attr_str(attr).as_deref() == Some("tags") {
895 skip |= attr.parse_args::<FieldTagArgs>().ok()?.skip;
896 }
897 }
898 let ty = &f.ty;
899 (!skip).then_some(quote! { <#ty as ::object_rainbow::Tagged>::TAGS })
900 })
901 .collect()
902}
903
904fn gen_tags(data: &Data, attrs: &[Attribute], errors: &mut Vec<Error>) -> proc_macro2::TokenStream {
905 match data {
906 Data::Struct(data) => {
907 let mut tags = Vec::new();
908 for attr in attrs {
909 if attr_str(attr).as_deref() == Some("tags") {
910 match attr.parse_args::<StructTagArgs>() {
911 Ok(mut args) => tags.append(&mut args.tags),
912 Err(e) => errors.push(e),
913 }
914 }
915 }
916 let nested = fields_tags(&data.fields);
917 if nested.len() == 1 && tags.is_empty() {
918 let nested = nested.into_iter().next().unwrap();
919 quote! {
920 #nested
921 }
922 } else {
923 quote! {
924 ::object_rainbow::Tags(&[#(#tags),*], &[#(&#nested),*])
925 }
926 }
927 }
928 Data::Enum(data) => {
929 let mut tags = Vec::new();
930 for attr in attrs {
931 if attr_str(attr).as_deref() == Some("tags") {
932 match attr.parse_args::<StructTagArgs>() {
933 Ok(mut args) => tags.append(&mut args.tags),
934 Err(e) => errors.push(e),
935 }
936 }
937 }
938 let mut nested: Vec<_> = data
939 .variants
940 .iter()
941 .flat_map(|v| fields_tags(&v.fields))
942 .collect();
943 let kind_tags = quote! {
944 <
945 <
946 <
947 Self
948 as
949 ::object_rainbow::Enum
950 >::Kind
951 as
952 ::object_rainbow::enumkind::EnumKind
953 >::Tag
954 as ::object_rainbow::Tagged
955 >::TAGS
956 };
957 nested.insert(0, kind_tags);
958 if nested.len() == 1 && tags.is_empty() {
959 let nested = nested.into_iter().next().unwrap();
960 quote! {
961 #nested
962 }
963 } else {
964 quote! {
965 ::object_rainbow::Tags(&[#(#tags),*], &[#(&#nested),*])
966 }
967 }
968 }
969 Data::Union(data) => {
970 Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
971 }
972 }
973}
974
975#[proc_macro_derive(Size)]
976pub fn derive_size(input: TokenStream) -> TokenStream {
977 let input = parse_macro_input!(input as DeriveInput);
978 let name = input.ident;
979 let size_arr = gen_size_arr(&input.data);
980 let size = gen_size(&input.data);
981 let generics = match bounds_size(input.generics.clone(), &input.data, &size_arr) {
982 Ok(g) => g,
983 Err(e) => return e.into_compile_error().into(),
984 };
985 let (_, ty_generics, where_clause) = generics.split_for_impl();
986 let mut generics = input.generics;
987 generics.params.push(parse_quote!(
988 __Output: ::object_rainbow::typenum::Unsigned
989 ));
990 let (impl_generics, _, _) = generics.split_for_impl();
991 let target = parse_for(&name, &input.attrs);
992 let output = quote! {
993 const _: () = {
994 use ::object_rainbow::typenum::tarr;
995
996 #[automatically_derived]
997 impl #impl_generics ::object_rainbow::Size for #target #ty_generics #where_clause {
998 const SIZE: usize = #size;
999
1000 type Size = <#size_arr as ::object_rainbow::typenum::FoldAdd>::Output;
1001 }
1002 };
1003 };
1004 TokenStream::from(output)
1005}
1006
1007fn bounds_size(
1008 mut generics: Generics,
1009 data: &Data,
1010 size_arr: &proc_macro2::TokenStream,
1011) -> syn::Result<Generics> {
1012 let g = &bounds_g(&generics);
1013 match data {
1014 Data::Struct(data) => {
1015 for f in data.fields.iter() {
1016 let ty = &f.ty;
1017 if type_contains_generics(GContext { g, always: false }, ty) {
1018 generics.make_where_clause().predicates.push(
1019 parse_quote_spanned! { ty.span() =>
1020 #ty: ::object_rainbow::Size
1021 },
1022 );
1023 }
1024 }
1025 }
1026 Data::Enum(data) => {
1027 for v in data.variants.iter() {
1028 for f in v.fields.iter() {
1029 let ty = &f.ty;
1030 if type_contains_generics(GContext { g, always: false }, ty) {
1031 generics.make_where_clause().predicates.push(
1032 parse_quote_spanned! { ty.span() =>
1033 #ty: ::object_rainbow::Size
1034 },
1035 );
1036 }
1037 }
1038 }
1039 for v in data.variants.iter().skip(1) {
1040 let arr = fields_size_arr(&v.fields, true);
1041 generics.make_where_clause().predicates.push(parse_quote!(
1042 #arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
1043 ));
1044 }
1045 }
1046 Data::Union(data) => {
1047 return Err(Error::new_spanned(
1048 data.union_token,
1049 "`union`s are not supported",
1050 ));
1051 }
1052 }
1053 generics.make_where_clause().predicates.push(parse_quote!(
1054 #size_arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
1055 ));
1056 Ok(generics)
1057}
1058
1059fn fields_size_arr(fields: &syn::Fields, as_enum: bool) -> proc_macro2::TokenStream {
1060 let kind_size = quote! {
1061 <
1062 <
1063 <
1064 Self
1065 as
1066 ::object_rainbow::Enum
1067 >::Kind
1068 as
1069 ::object_rainbow::enumkind::EnumKind
1070 >::Tag
1071 as ::object_rainbow::Size
1072 >::Size
1073 };
1074 if fields.is_empty() {
1075 return if as_enum {
1076 quote! { tarr![#kind_size, ::object_rainbow::typenum::consts::U0] }
1077 } else {
1078 quote! { tarr![::object_rainbow::typenum::consts::U0] }
1079 };
1080 }
1081 let size_arr = fields.iter().map(|f| {
1082 let ty = &f.ty;
1083 quote! { <#ty as ::object_rainbow::Size>::Size }
1084 });
1085 if as_enum {
1086 quote! { tarr![#kind_size, #(#size_arr),*] }
1087 } else {
1088 quote! { tarr![#(#size_arr),*] }
1089 }
1090}
1091
1092fn gen_size_arr(data: &Data) -> proc_macro2::TokenStream {
1093 match data {
1094 Data::Struct(data) => fields_size_arr(&data.fields, false),
1095 Data::Enum(data) => {
1096 if let Some(v) = data.variants.first() {
1097 fields_size_arr(&v.fields, true)
1098 } else {
1099 Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
1100 .into_compile_error()
1101 }
1102 }
1103 Data::Union(data) => {
1104 Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1105 }
1106 }
1107}
1108
1109fn fields_size(fields: &syn::Fields) -> proc_macro2::TokenStream {
1110 if fields.is_empty() {
1111 return quote! {0};
1112 }
1113 let size = fields.iter().map(|f| {
1114 let ty = &f.ty;
1115 quote! { <#ty as ::object_rainbow::Size>::SIZE }
1116 });
1117 quote! {
1118 #(#size)+*
1119 }
1120}
1121
1122fn gen_size(data: &Data) -> proc_macro2::TokenStream {
1123 match data {
1124 Data::Struct(data) => fields_size(&data.fields),
1125 Data::Enum(data) => {
1126 if let Some(v) = data.variants.first() {
1127 let size = fields_size(&v.fields);
1128 let kind_size = quote! {
1129 <
1130 <
1131 <
1132 Self
1133 as
1134 ::object_rainbow::Enum
1135 >::Kind
1136 as
1137 ::object_rainbow::enumkind::EnumKind
1138 >::Tag
1139 as ::object_rainbow::Size
1140 >::SIZE
1141 };
1142 quote! { #kind_size + #size }
1143 } else {
1144 Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
1145 .into_compile_error()
1146 }
1147 }
1148 Data::Union(data) => {
1149 Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1150 }
1151 }
1152}
1153
1154#[proc_macro_derive(Parse, attributes(parse))]
1155pub fn derive_parse(input: TokenStream) -> TokenStream {
1156 let input = parse_macro_input!(input as DeriveInput);
1157 let name = input.ident;
1158 let generics = input.generics.clone();
1159 let (_, ty_generics, _) = generics.split_for_impl();
1160 let mut defs = Vec::new();
1161 let generics = match bounds_parse(input.generics, &input.data, &input.attrs, &name, &mut defs) {
1162 Ok(g) => g,
1163 Err(e) => return e.into_compile_error().into(),
1164 };
1165 let parse = gen_parse(&input.data, &ty_generics);
1166 let (impl_generics, _, where_clause) = generics.split_for_impl();
1167 let target = parse_for(&name, &input.attrs);
1168 let output = quote! {
1169 const _: () = {
1170 #(#defs)*
1171
1172 #[automatically_derived]
1173 impl #impl_generics ::object_rainbow::Parse<__I> for #target #ty_generics
1174 #where_clause
1175 {
1176 fn parse(mut input: __I) -> ::object_rainbow::Result<Self> {
1177 #parse
1178 }
1179 }
1180 };
1181 };
1182 TokenStream::from(output)
1183}
1184
1185#[derive(Debug, FromMeta)]
1186#[darling(derive_syn_parse)]
1187struct ParseArgs {
1188 bound: Option<Type>,
1189 #[darling(default)]
1190 unchecked: bool,
1191 with: Option<Expr>,
1192 #[darling(default, rename = "unstable_mutual")]
1193 mutual: bool,
1194}
1195
1196fn conditional_parse_name(f: &Field, inline: bool) -> Ident {
1197 let infix = if inline { "ParseInline" } else { "Parse" };
1198 let conditional = format!("__Conditional{infix}_{}", f.ident.as_ref().unwrap());
1199 Ident::new(&conditional, f.span())
1200}
1201
1202fn conditional_parse_input(inline: bool) -> proc_macro2::TokenStream {
1203 if inline {
1204 quote!(&mut impl ::object_rainbow::PointInput<Extra = Self::E>)
1205 } else {
1206 quote!(impl ::object_rainbow::PointInput<Extra = Self::E>)
1207 }
1208}
1209
1210fn conditional_parse_method(inline: bool) -> proc_macro2::TokenStream {
1211 if inline {
1212 quote!(parse_inline)
1213 } else {
1214 quote!(parse)
1215 }
1216}
1217
1218fn bounds_parse(
1219 mut generics: Generics,
1220 data: &Data,
1221 attrs: &[Attribute],
1222 name: &Ident,
1223 defs: &mut Vec<proc_macro2::TokenStream>,
1224) -> syn::Result<Generics> {
1225 let g_clone = generics.clone();
1226 let (impl_generics, ty_generics, where_clause) = g_clone.split_for_impl();
1227 let this = quote_spanned! { name.span() =>
1228 #name #ty_generics
1229 };
1230 let (recursive, _) = parse_recursive_inline(attrs)?;
1231 let tr = |last| match (last, recursive) {
1232 (true, true) => {
1233 quote!(::object_rainbow::Parse<__I> + ::object_rainbow::Object<__I::Extra>)
1234 }
1235 (true, false) => quote!(::object_rainbow::Parse<__I>),
1236 (false, true) => {
1237 quote!(::object_rainbow::ParseInline<__I> + ::object_rainbow::Inline<__I::Extra>)
1238 }
1239 (false, false) => quote!(::object_rainbow::ParseInline<__I>),
1240 };
1241 match data {
1242 Data::Struct(data) => {
1243 let last_at = data.fields.len().checked_sub(1).unwrap_or_default();
1244 'field: for (i, f) in data.fields.iter().enumerate() {
1245 let last = i == last_at;
1246 let ty = &f.ty;
1247 let mut b = None;
1248 for attr in &f.attrs {
1249 if attr_str(attr).as_deref() == Some("parse") {
1250 let ParseArgs {
1251 bound,
1252 unchecked,
1253 mutual,
1254 ..
1255 } = attr.parse_args::<ParseArgs>()?;
1256 if mutual {
1257 let conditional = conditional_parse_name(f, !last);
1258 let mut g_clone = g_clone.clone();
1259 g_clone.params.push(parse_quote!(
1260 __E: ::core::marker::Send + ::core::marker::Sync
1261 ));
1262 let (impl_generics_extra, _, _) = g_clone.split_for_impl();
1263 let input_type = conditional_parse_input(!last);
1264 let parse_method = conditional_parse_method(!last);
1265 defs.push(quote! {
1266 #[allow(non_camel_case_types)]
1267 trait #conditional #impl_generics: ::object_rainbow::BoundPair
1268 #where_clause
1269 {
1270 fn parse(
1271 input: #input_type,
1272 ) -> ::object_rainbow::Result<Self::T>
1273 where #this: ::object_rainbow::Object<Self::E>;
1274 }
1275
1276 impl #impl_generics_extra #conditional #ty_generics
1277 for (#ty, __E)
1278 #where_clause
1279 {
1280 fn parse(
1281 input: #input_type,
1282 ) -> ::object_rainbow::Result<Self::T>
1283 where #this: ::object_rainbow::Object<Self::E> {
1284 input.#parse_method::<Self::T>()
1285 }
1286 }
1287 });
1288 b = Some(parse_quote!(#conditional #ty_generics));
1289 }
1290 if unchecked {
1291 continue 'field;
1292 }
1293 if let Some(bound) = bound {
1294 b = Some(bound);
1295 }
1296 }
1297 }
1298 if let Some(bound) = b {
1299 generics.make_where_clause().predicates.push(
1300 parse_quote_spanned! { ty.span() =>
1301 (#ty, __I::Extra): ::object_rainbow::BoundPair<
1302 T = #ty, E = __I::Extra
1303 > + #bound
1304 },
1305 );
1306 } else {
1307 let tr = tr(last);
1308 generics.make_where_clause().predicates.push(
1309 parse_quote_spanned! { ty.span() =>
1310 #ty: #tr
1311 },
1312 );
1313 }
1314 }
1315 }
1316 Data::Enum(data) => {
1317 for v in data.variants.iter() {
1318 let last_at = v.fields.len().checked_sub(1).unwrap_or_default();
1319 'field: for (i, f) in v.fields.iter().enumerate() {
1320 let ty = &f.ty;
1321 let mut b = None;
1322 for attr in &f.attrs {
1323 if attr_str(attr).as_deref() == Some("parse") {
1324 let ParseArgs {
1325 bound, unchecked, ..
1326 } = attr.parse_args::<ParseArgs>()?;
1327 if unchecked {
1328 continue 'field;
1329 }
1330 if let Some(bound) = bound {
1331 b = Some(bound);
1332 }
1333 }
1334 }
1335 if let Some(bound) = b {
1336 generics.make_where_clause().predicates.push(
1337 parse_quote_spanned! { ty.span() =>
1338 (#ty, __I::Extra): ::object_rainbow::BoundPair<
1339 T = #ty, E = __I::Extra
1340 > + #bound
1341 },
1342 );
1343 } else {
1344 let last = i == last_at;
1345 let tr = tr(last);
1346 generics.make_where_clause().predicates.push(
1347 parse_quote_spanned! { ty.span() =>
1348 #ty: #tr
1349 },
1350 );
1351 }
1352 }
1353 }
1354 }
1355 Data::Union(data) => {
1356 return Err(Error::new_spanned(
1357 data.union_token,
1358 "`union`s are not supported",
1359 ));
1360 }
1361 }
1362 generics.params.push(if recursive {
1363 parse_quote!(__I: ::object_rainbow::PointInput<
1364 Extra: ::core::marker::Send + ::core::marker::Sync + ::core::clone::Clone
1365 >)
1366 } else {
1367 parse_quote!(__I: ::object_rainbow::ParseInput)
1368 });
1369 Ok(generics)
1370}
1371
1372fn gen_parse(data: &Data, ty_generics: &TypeGenerics<'_>) -> proc_macro2::TokenStream {
1373 match data {
1374 Data::Struct(data) => {
1375 let arm = fields_parse(&data.fields, ty_generics);
1376 quote! { Ok(Self #arm)}
1377 }
1378 Data::Enum(data) => {
1379 let parse = data.variants.iter().map(|v| {
1380 let ident = &v.ident;
1381 let arm = fields_parse(&v.fields, ty_generics);
1382 quote! {
1383 <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
1384 }
1385 });
1386 quote! {
1387 Ok(match input.parse_inline()? {
1388 #(#parse)*
1389 })
1390 }
1391 }
1392 Data::Union(data) => {
1393 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1394 }
1395 }
1396}
1397
1398fn fields_parse(fields: &syn::Fields, ty_generics: &TypeGenerics<'_>) -> proc_macro2::TokenStream {
1399 let last_at = fields.len().checked_sub(1).unwrap_or_default();
1400 match fields {
1401 syn::Fields::Named(fields) => {
1402 let parse = fields.named.iter().enumerate().map(|(i, f)| {
1403 let last = i == last_at;
1404 let ty = &f.ty;
1405 let mut w = None;
1406 let mut b = None;
1407 for attr in &f.attrs {
1408 if attr_str(attr).as_deref() == Some("parse") {
1409 let ParseArgs {
1410 with,
1411 bound,
1412 mutual,
1413 ..
1414 } = match attr.parse_args::<ParseArgs>() {
1415 Ok(args) => args,
1416 Err(e) => return e.into_compile_error(),
1417 };
1418 if mutual {
1419 let conditional = format!(
1420 "__Conditional{}_{}",
1421 if last { "Parse" } else { "ParseInline" },
1422 f.ident.as_ref().unwrap(),
1423 );
1424 let conditional = Ident::new(&conditional, f.span());
1425 w = Some(parse_quote!(parse));
1426 b = Some(parse_quote!(#conditional #ty_generics));
1427 }
1428 if let Some(with) = with {
1429 w = Some(with);
1430 }
1431 if let Some(bound) = bound {
1432 b = Some(bound);
1433 }
1434 }
1435 }
1436 let i = f.ident.as_ref().unwrap();
1437 if let Some(with) = w {
1438 let arg = if last {
1439 quote!(input)
1440 } else {
1441 quote!(&mut input)
1442 };
1443 if let Some(bound) = b {
1444 quote_spanned! { f.ty.span() =>
1445 #i: <(#ty, __I::Extra) as #bound>::#with(#arg)?
1446 }
1447 } else {
1448 quote_spanned! { f.ty.span() =>
1449 #i: #with(#arg)?
1450 }
1451 }
1452 } else {
1453 let method = if last {
1454 quote!(parse)
1455 } else {
1456 quote!(parse_inline)
1457 };
1458 quote_spanned! { f.ty.span() =>
1459 #i: input.#method()?
1460 }
1461 }
1462 });
1463 quote! { { #(#parse),* } }
1464 }
1465 syn::Fields::Unnamed(fields) => {
1466 let parse = fields.unnamed.iter().enumerate().map(|(i, f)| {
1467 let ty = &f.ty;
1468 let mut w = None;
1469 let mut b = None;
1470 for attr in &f.attrs {
1471 if attr_str(attr).as_deref() == Some("parse") {
1472 let ParseArgs { with, bound, .. } = match attr.parse_args::<ParseArgs>() {
1473 Ok(args) => args,
1474 Err(e) => return e.into_compile_error(),
1475 };
1476 if let Some(with) = with {
1477 w = Some(with);
1478 }
1479 if let Some(bound) = bound {
1480 b = Some(bound);
1481 }
1482 }
1483 }
1484 let last = i == last_at;
1485 if let Some(with) = w {
1486 let arg = if last {
1487 quote!(input)
1488 } else {
1489 quote!(&mut input)
1490 };
1491 if let Some(bound) = b {
1492 quote_spanned! { f.ty.span() =>
1493 <(#ty, __I::Extra) as #bound>::#with(#arg)?
1494 }
1495 } else {
1496 quote_spanned! { f.ty.span() =>
1497 #with(#arg)?
1498 }
1499 }
1500 } else {
1501 let method = if last {
1502 quote!(parse)
1503 } else {
1504 quote!(parse_inline)
1505 };
1506 quote_spanned! { f.ty.span() =>
1507 input.#method()?
1508 }
1509 }
1510 });
1511 quote! { (#(#parse),*) }
1512 }
1513 syn::Fields::Unit => quote! {},
1514 }
1515}
1516
1517#[proc_macro_derive(ParseInline, attributes(parse))]
1518pub fn derive_parse_inline(input: TokenStream) -> TokenStream {
1519 let input = parse_macro_input!(input as DeriveInput);
1520 let name = input.ident;
1521 let generics = input.generics.clone();
1522 let (_, ty_generics, _) = generics.split_for_impl();
1523 let generics = match bounds_parse_inline(input.generics, &input.data, &input.attrs) {
1524 Ok(g) => g,
1525 Err(e) => return e.into_compile_error().into(),
1526 };
1527 let parse_inline = gen_parse_inline(&input.data);
1528 let (impl_generics, _, where_clause) = generics.split_for_impl();
1529 let target = parse_for(&name, &input.attrs);
1530 let output = quote! {
1531 #[automatically_derived]
1532 impl #impl_generics ::object_rainbow::ParseInline<__I> for #target #ty_generics #where_clause {
1533 fn parse_inline(input: &mut __I) -> ::object_rainbow::Result<Self> {
1534 #parse_inline
1535 }
1536 }
1537 };
1538 TokenStream::from(output)
1539}
1540
1541fn bounds_parse_inline(
1542 mut generics: Generics,
1543 data: &Data,
1544 attrs: &[Attribute],
1545) -> syn::Result<Generics> {
1546 let (recursive, _) = parse_recursive_inline(attrs)?;
1547 let tr = if recursive {
1548 quote!(::object_rainbow::ParseInline<__I> + ::object_rainbow::Inline<__I::Extra>)
1549 } else {
1550 quote!(::object_rainbow::ParseInline<__I>)
1551 };
1552 match data {
1553 Data::Struct(data) => {
1554 'field: for f in data.fields.iter() {
1555 let ty = &f.ty;
1556 let mut b = None;
1557 for attr in &f.attrs {
1558 if attr_str(attr).as_deref() == Some("parse") {
1559 let ParseArgs {
1560 bound, unchecked, ..
1561 } = attr.parse_args::<ParseArgs>()?;
1562 if unchecked {
1563 continue 'field;
1564 }
1565 if let Some(bound) = bound {
1566 b = Some(bound);
1567 }
1568 }
1569 }
1570 if let Some(bound) = b {
1571 generics.make_where_clause().predicates.push(
1572 parse_quote_spanned! { ty.span() =>
1573 (#ty, __I::Extra): #bound
1574 },
1575 );
1576 } else {
1577 generics.make_where_clause().predicates.push(
1578 parse_quote_spanned! { ty.span() =>
1579 #ty: #tr
1580 },
1581 );
1582 }
1583 }
1584 }
1585 Data::Enum(data) => {
1586 for v in data.variants.iter() {
1587 'field: for f in v.fields.iter() {
1588 let ty = &f.ty;
1589 let mut b = None;
1590 for attr in &f.attrs {
1591 if attr_str(attr).as_deref() == Some("parse") {
1592 let ParseArgs {
1593 bound, unchecked, ..
1594 } = attr.parse_args::<ParseArgs>()?;
1595 if unchecked {
1596 continue 'field;
1597 }
1598 if let Some(bound) = bound {
1599 b = Some(bound);
1600 }
1601 }
1602 }
1603 if let Some(bound) = b {
1604 generics.make_where_clause().predicates.push(
1605 parse_quote_spanned! { ty.span() =>
1606 (#ty, __I::Extra): #bound
1607 },
1608 );
1609 } else {
1610 generics.make_where_clause().predicates.push(
1611 parse_quote_spanned! { ty.span() =>
1612 #ty: #tr
1613 },
1614 );
1615 }
1616 }
1617 }
1618 }
1619 Data::Union(data) => {
1620 return Err(Error::new_spanned(
1621 data.union_token,
1622 "`union`s are not supported",
1623 ));
1624 }
1625 }
1626 generics.params.push(if recursive {
1627 parse_quote!(__I: ::object_rainbow::PointInput<
1628 Extra: ::core::marker::Send + ::core::marker::Sync
1629 >)
1630 } else {
1631 parse_quote!(__I: ::object_rainbow::ParseInput)
1632 });
1633 Ok(generics)
1634}
1635
1636fn fields_parse_inline(fields: &syn::Fields) -> proc_macro2::TokenStream {
1637 match fields {
1638 syn::Fields::Named(fields) => {
1639 let parse = fields.named.iter().map(|f| {
1640 let i = f.ident.as_ref().unwrap();
1641 quote_spanned! { f.ty.span() =>
1642 #i: input.parse_inline()?
1643 }
1644 });
1645 quote! { { #(#parse),* } }
1646 }
1647 syn::Fields::Unnamed(fields) => {
1648 let parse = fields.unnamed.iter().map(|f| {
1649 quote_spanned! { f.ty.span() =>
1650 input.parse_inline()?
1651 }
1652 });
1653 quote! { (#(#parse),*) }
1654 }
1655 syn::Fields::Unit => quote! {},
1656 }
1657}
1658
1659fn gen_parse_inline(data: &Data) -> proc_macro2::TokenStream {
1660 match data {
1661 Data::Struct(data) => {
1662 let arm = fields_parse_inline(&data.fields);
1663 quote! { Ok(Self #arm) }
1664 }
1665 Data::Enum(data) => {
1666 let parse_inline = data.variants.iter().map(|v| {
1667 let ident = &v.ident;
1668 let arm = fields_parse_inline(&v.fields);
1669 quote! {
1670 <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
1671 }
1672 });
1673 quote! {
1674 Ok(match input.parse_inline()? {
1675 #(#parse_inline)*
1676 })
1677 }
1678 }
1679 Data::Union(data) => {
1680 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1681 }
1682 }
1683}
1684
1685#[proc_macro_derive(ParseAsInline)]
1686pub fn derive_parse_as_inline(input: TokenStream) -> TokenStream {
1687 let input = parse_macro_input!(input as DeriveInput);
1688 let name = input.ident;
1689 let generics = input.generics.clone();
1690 let (_, ty_generics, _) = generics.split_for_impl();
1691 let generics = match bounds_parse_as_inline(input.generics, &name) {
1692 Ok(g) => g,
1693 Err(e) => return e.into_compile_error().into(),
1694 };
1695 let (impl_generics, _, where_clause) = generics.split_for_impl();
1696 let target = parse_for(&name, &input.attrs);
1697 let output = quote! {
1698 #[automatically_derived]
1699 impl #impl_generics ::object_rainbow::Parse<__I> for #target #ty_generics #where_clause {
1700 fn parse(input: __I) -> ::object_rainbow::Result<Self> {
1701 ::object_rainbow::ParseInline::<__I>::parse_as_inline(input)
1702 }
1703 }
1704 };
1705 TokenStream::from(output)
1706}
1707
1708fn bounds_parse_as_inline(mut generics: Generics, name: &Ident) -> syn::Result<Generics> {
1709 generics
1710 .make_where_clause()
1711 .predicates
1712 .push(parse_quote_spanned! { name.span() =>
1713 Self: ::object_rainbow::ParseInline::<__I>
1714 });
1715 generics
1716 .params
1717 .push(parse_quote!(__I: ::object_rainbow::ParseInput));
1718 Ok(generics)
1719}
1720
1721fn parse_path(attr: &Attribute) -> syn::Result<Type> {
1722 attr.parse_args::<LitStr>()?.parse()
1723}
1724
1725fn attr_str(attr: &Attribute) -> Option<String> {
1726 Some(attr.path().get_ident()?.to_string())
1727}
1728
1729#[proc_macro_derive(Enum, attributes(enumtag))]
1730pub fn derive_enum(input: TokenStream) -> TokenStream {
1731 let input = parse_macro_input!(input as DeriveInput);
1732 let name = input.ident;
1733 let generics = input.generics.clone();
1734 let (_, ty_generics, _) = generics.split_for_impl();
1735 let generics = input.generics;
1736 let variants = gen_variants(&input.data);
1737 let variant_count = gen_variant_count(&input.data);
1738 let to_tag = gen_to_tag(&input.data);
1739 let from_tag = gen_from_tag(&input.data);
1740 let kind = gen_kind(&input.data);
1741 let (impl_generics, _, where_clause) = generics.split_for_impl();
1742 let mut errors = Vec::new();
1743 let mut enumtag = None;
1744 for attr in &input.attrs {
1745 if attr_str(attr).as_deref() == Some("enumtag") {
1746 match parse_path(attr) {
1747 Ok(path) => {
1748 if enumtag.is_some() {
1749 errors.push(Error::new_spanned(path, "duplicate tag"));
1750 } else {
1751 enumtag = Some(path);
1752 }
1753 }
1754 Err(e) => errors.push(e),
1755 }
1756 }
1757 }
1758 let enumtag = enumtag
1759 .unwrap_or_else(|| parse_quote!(::object_rainbow::numeric::Le<::core::num::NonZero<u8>>));
1760 let errors = errors.into_iter().map(|e| e.into_compile_error());
1761 let target = parse_for(&name, &input.attrs);
1762 let output = quote! {
1763 const _: () = {
1764 #(#errors)*
1765
1766 use ::object_rainbow::enumkind::EnumKind;
1767
1768 #[derive(Clone, Copy, ::object_rainbow::ParseAsInline)]
1769 pub enum __Kind {
1770 #variants
1771 }
1772
1773 #[automatically_derived]
1774 impl ::object_rainbow::enumkind::EnumKind for __Kind {
1775 type Tag = ::object_rainbow::enumkind::EnumTag<
1776 #enumtag,
1777 #variant_count,
1778 >;
1779
1780 fn to_tag(self) -> Self::Tag {
1781 #to_tag
1782 }
1783
1784 fn from_tag(tag: Self::Tag) -> Self {
1785 #from_tag
1786 }
1787 }
1788
1789 impl<I: ::object_rainbow::ParseInput> ::object_rainbow::ParseInline<I> for __Kind {
1790 fn parse_inline(input: &mut I) -> ::object_rainbow::Result<Self> {
1791 Ok(::object_rainbow::enumkind::EnumKind::from_tag(input.parse_inline()?))
1792 }
1793 }
1794
1795 #[automatically_derived]
1796 impl #impl_generics ::object_rainbow::Enum for #target #ty_generics #where_clause {
1797 type Kind = __Kind;
1798
1799 fn kind(&self) -> Self::Kind {
1800 #kind
1801 }
1802 }
1803 };
1804 };
1805 TokenStream::from(output)
1806}
1807
1808fn gen_variants(data: &Data) -> proc_macro2::TokenStream {
1809 match data {
1810 Data::Struct(data) => {
1811 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1812 }
1813 Data::Enum(data) => {
1814 let variants = data.variants.iter().map(|v| &v.ident);
1815 quote! { #(#variants),* }
1816 }
1817 Data::Union(data) => {
1818 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1819 }
1820 }
1821}
1822
1823fn gen_variant_count(data: &Data) -> proc_macro2::TokenStream {
1824 match data {
1825 Data::Struct(data) => {
1826 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1827 }
1828 Data::Enum(data) => {
1829 let variant_count = data.variants.len();
1830 quote! { #variant_count }
1831 }
1832 Data::Union(data) => {
1833 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1834 }
1835 }
1836}
1837
1838fn gen_to_tag(data: &Data) -> proc_macro2::TokenStream {
1839 match data {
1840 Data::Struct(data) => {
1841 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1842 }
1843 Data::Enum(data) => {
1844 let to_tag = data.variants.iter().enumerate().map(|(i, v)| {
1845 let ident = &v.ident;
1846 quote_spanned! { ident.span() =>
1847 Self::#ident => ::object_rainbow::enumkind::EnumTag::from_const::<#i>(),
1848 }
1849 });
1850 quote! {
1851 match self {
1852 #(#to_tag)*
1853 }
1854 }
1855 }
1856 Data::Union(data) => {
1857 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1858 }
1859 }
1860}
1861
1862fn gen_from_tag(data: &Data) -> proc_macro2::TokenStream {
1863 match data {
1864 Data::Struct(data) => {
1865 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1866 }
1867 Data::Enum(data) => {
1868 let from_tag = data.variants.iter().enumerate().map(|(i, v)| {
1869 let ident = &v.ident;
1870 quote_spanned! { ident.span() =>
1871 #i => Self::#ident,
1872 }
1873 });
1874 quote! {
1875 match tag.to_usize() {
1876 #(#from_tag)*
1877 _ => unreachable!(),
1878 }
1879 }
1880 }
1881 Data::Union(data) => {
1882 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1883 }
1884 }
1885}
1886
1887fn gen_kind(data: &Data) -> proc_macro2::TokenStream {
1888 match data {
1889 Data::Struct(data) => {
1890 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1891 }
1892 Data::Enum(data) => {
1893 let variants = data.variants.iter().map(|v| {
1894 let ident = &v.ident;
1895 quote_spanned! { ident.span() =>
1896 Self::#ident {..} => __Kind::#ident,
1897 }
1898 });
1899 quote! {
1900 match self {
1901 #(#variants)*
1902 }
1903 }
1904 }
1905 Data::Union(data) => {
1906 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1907 }
1908 }
1909}
1910
1911#[proc_macro_derive(MaybeHasNiche)]
1912pub fn derive_maybe_has_niche(input: TokenStream) -> TokenStream {
1913 let input = parse_macro_input!(input as DeriveInput);
1914 let name = input.ident;
1915 let mn_array = gen_mn_array(&input.data);
1916 let (_, ty_generics, _) = input.generics.split_for_impl();
1917 let generics = match bounds_maybe_has_niche(input.generics.clone(), &input.data) {
1918 Ok(g) => g,
1919 Err(e) => return e.into_compile_error().into(),
1920 };
1921 let (impl_generics, _, where_clause) = generics.split_for_impl();
1922 let target = parse_for(&name, &input.attrs);
1923 let output = quote! {
1924 const _: () = {
1925 use ::object_rainbow::typenum::tarr;
1926
1927 #[automatically_derived]
1928 impl #impl_generics ::object_rainbow::MaybeHasNiche for #target #ty_generics #where_clause {
1929 type MnArray = #mn_array;
1930 }
1931 };
1932 };
1933 TokenStream::from(output)
1934}
1935
1936fn bounds_maybe_has_niche(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
1937 match data {
1938 Data::Struct(data) => {
1939 for f in data.fields.iter() {
1940 let ty = &f.ty;
1941 generics
1942 .make_where_clause()
1943 .predicates
1944 .push(parse_quote_spanned! { ty.span() =>
1945 #ty: ::object_rainbow::MaybeHasNiche<
1946 MnArray: ::object_rainbow::MnArray<
1947 MaybeNiche: ::object_rainbow::MaybeNiche
1948 >
1949 >
1950 });
1951 }
1952 }
1953 Data::Enum(data) => {
1954 generics.params.push(parse_quote!(
1955 __N: ::object_rainbow::typenum::Unsigned
1956 ));
1957 for (i, v) in data.variants.iter().enumerate() {
1958 let mn_array = fields_mn_array(&v.fields, Some(i));
1959 generics
1960 .make_where_clause()
1961 .predicates
1962 .push(parse_quote_spanned! { v.span() =>
1963 #mn_array: ::object_rainbow::MnArray<
1964 MaybeNiche: ::object_rainbow::NicheOr<N = __N>
1965 >
1966 });
1967 for f in v.fields.iter() {
1968 let ty = &f.ty;
1969 generics.make_where_clause().predicates.push(
1970 parse_quote_spanned! { ty.span() =>
1971 #ty: ::object_rainbow::MaybeHasNiche<
1972 MnArray: ::object_rainbow::MnArray<
1973 MaybeNiche: ::object_rainbow::MaybeNiche
1974 >
1975 >
1976 },
1977 );
1978 }
1979 }
1980 }
1981 Data::Union(data) => {
1982 return Err(Error::new_spanned(
1983 data.union_token,
1984 "`union`s are not supported",
1985 ));
1986 }
1987 }
1988 Ok(generics)
1989}
1990
1991fn fields_mn_array(fields: &syn::Fields, variant: Option<usize>) -> proc_macro2::TokenStream {
1992 let mn_array = fields.iter().map(|f| {
1993 let ty = &f.ty;
1994 quote! {
1995 <
1996 <
1997 #ty
1998 as
1999 ::object_rainbow::MaybeHasNiche
2000 >::MnArray
2001 as
2002 ::object_rainbow::MnArray
2003 >::MaybeNiche
2004 }
2005 });
2006 if let Some(variant) = variant {
2007 let kind_niche = quote! {
2008 ::object_rainbow::AutoEnumNiche<Self, #variant>
2009 };
2010 quote! { tarr![#kind_niche, ::object_rainbow::NoNiche<::object_rainbow::HackNiche<#variant>>, #(#mn_array),*] }
2011 } else {
2012 quote! { tarr![#(#mn_array),*] }
2013 }
2014}
2015
2016fn gen_mn_array(data: &Data) -> proc_macro2::TokenStream {
2017 match data {
2018 Data::Struct(data) => fields_mn_array(&data.fields, None),
2019 Data::Enum(data) => {
2020 let mn_array = data.variants.iter().enumerate().map(|(i, v)| {
2021 let mn_array = fields_mn_array(&v.fields, Some(i));
2022 quote! { <#mn_array as ::object_rainbow::MnArray>::MaybeNiche }
2023 });
2024 quote! {
2025 ::object_rainbow::NicheFoldOrArray<tarr![#(#mn_array),*]>
2026 }
2027 }
2028 Data::Union(data) => {
2029 Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
2030 }
2031 }
2032}