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, is_enum) = 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 if is_enum {
988 generics.params.push(parse_quote!(
989 __Output: ::object_rainbow::typenum::Unsigned
990 ));
991 }
992 let (impl_generics, _, _) = generics.split_for_impl();
993 let target = parse_for(&name, &input.attrs);
994 let output = quote! {
995 const _: () = {
996 use ::object_rainbow::typenum::tarr;
997
998 #[automatically_derived]
999 impl #impl_generics ::object_rainbow::Size for #target #ty_generics #where_clause {
1000 const SIZE: usize = #size;
1001
1002 type Size = <#size_arr as ::object_rainbow::typenum::FoldAdd>::Output;
1003 }
1004 };
1005 };
1006 TokenStream::from(output)
1007}
1008
1009fn bounds_size(
1010 mut generics: Generics,
1011 data: &Data,
1012 size_arr: &proc_macro2::TokenStream,
1013) -> syn::Result<(Generics, bool)> {
1014 let g = &bounds_g(&generics);
1015 let is_enum = match data {
1016 Data::Struct(data) => {
1017 for f in data.fields.iter() {
1018 let ty = &f.ty;
1019 if type_contains_generics(GContext { g, always: false }, ty) {
1020 generics.make_where_clause().predicates.push(
1021 parse_quote_spanned! { ty.span() =>
1022 #ty: ::object_rainbow::Size
1023 },
1024 );
1025 }
1026 }
1027 generics.make_where_clause().predicates.push(parse_quote!(
1028 #size_arr: ::object_rainbow::typenum::FoldAdd<
1029 Output: ::object_rainbow::typenum::Unsigned
1030 >
1031 ));
1032 false
1033 }
1034 Data::Enum(data) => {
1035 for v in data.variants.iter() {
1036 for f in v.fields.iter() {
1037 let ty = &f.ty;
1038 if type_contains_generics(GContext { g, always: false }, ty) {
1039 generics.make_where_clause().predicates.push(
1040 parse_quote_spanned! { ty.span() =>
1041 #ty: ::object_rainbow::Size
1042 },
1043 );
1044 }
1045 }
1046 }
1047 for v in data.variants.iter().skip(1) {
1048 let arr = fields_size_arr(&v.fields, true);
1049 generics.make_where_clause().predicates.push(parse_quote!(
1050 #arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
1051 ));
1052 }
1053 generics.make_where_clause().predicates.push(parse_quote!(
1054 #size_arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
1055 ));
1056 true
1057 }
1058 Data::Union(data) => {
1059 return Err(Error::new_spanned(
1060 data.union_token,
1061 "`union`s are not supported",
1062 ));
1063 }
1064 };
1065 Ok((generics, is_enum))
1066}
1067
1068fn fields_size_arr(fields: &syn::Fields, as_enum: bool) -> proc_macro2::TokenStream {
1069 let kind_size = quote! {
1070 <
1071 <
1072 <
1073 Self
1074 as
1075 ::object_rainbow::Enum
1076 >::Kind
1077 as
1078 ::object_rainbow::enumkind::EnumKind
1079 >::Tag
1080 as ::object_rainbow::Size
1081 >::Size
1082 };
1083 if fields.is_empty() {
1084 return if as_enum {
1085 quote! { tarr![#kind_size, ::object_rainbow::typenum::consts::U0] }
1086 } else {
1087 quote! { tarr![::object_rainbow::typenum::consts::U0] }
1088 };
1089 }
1090 let size_arr = fields.iter().map(|f| {
1091 let ty = &f.ty;
1092 quote! { <#ty as ::object_rainbow::Size>::Size }
1093 });
1094 if as_enum {
1095 quote! { tarr![#kind_size, ::object_rainbow::typenum::consts::U0, #(#size_arr),*] }
1096 } else {
1097 quote! { tarr![::object_rainbow::typenum::consts::U0, #(#size_arr),*] }
1098 }
1099}
1100
1101fn gen_size_arr(data: &Data) -> proc_macro2::TokenStream {
1102 match data {
1103 Data::Struct(data) => fields_size_arr(&data.fields, false),
1104 Data::Enum(data) => {
1105 if let Some(v) = data.variants.first() {
1106 fields_size_arr(&v.fields, true)
1107 } else {
1108 Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
1109 .into_compile_error()
1110 }
1111 }
1112 Data::Union(data) => {
1113 Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1114 }
1115 }
1116}
1117
1118fn fields_size(fields: &syn::Fields) -> proc_macro2::TokenStream {
1119 if fields.is_empty() {
1120 return quote! {0};
1121 }
1122 let size = fields.iter().map(|f| {
1123 let ty = &f.ty;
1124 quote! { <#ty as ::object_rainbow::Size>::SIZE }
1125 });
1126 quote! {
1127 #(#size)+*
1128 }
1129}
1130
1131fn gen_size(data: &Data) -> proc_macro2::TokenStream {
1132 match data {
1133 Data::Struct(data) => fields_size(&data.fields),
1134 Data::Enum(data) => {
1135 if let Some(v) = data.variants.first() {
1136 let size = fields_size(&v.fields);
1137 let kind_size = quote! {
1138 <
1139 <
1140 <
1141 Self
1142 as
1143 ::object_rainbow::Enum
1144 >::Kind
1145 as
1146 ::object_rainbow::enumkind::EnumKind
1147 >::Tag
1148 as ::object_rainbow::Size
1149 >::SIZE
1150 };
1151 quote! { #kind_size + #size }
1152 } else {
1153 Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
1154 .into_compile_error()
1155 }
1156 }
1157 Data::Union(data) => {
1158 Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1159 }
1160 }
1161}
1162
1163#[proc_macro_derive(Parse, attributes(parse))]
1164pub fn derive_parse(input: TokenStream) -> TokenStream {
1165 let input = parse_macro_input!(input as DeriveInput);
1166 let name = input.ident;
1167 let generics = input.generics.clone();
1168 let (_, ty_generics, _) = generics.split_for_impl();
1169 let mut defs = Vec::new();
1170 let generics = match bounds_parse(input.generics, &input.data, &input.attrs, &name, &mut defs) {
1171 Ok(g) => g,
1172 Err(e) => return e.into_compile_error().into(),
1173 };
1174 let parse = gen_parse(&input.data, &ty_generics);
1175 let (impl_generics, _, where_clause) = generics.split_for_impl();
1176 let target = parse_for(&name, &input.attrs);
1177 let output = quote! {
1178 const _: () = {
1179 #(#defs)*
1180
1181 #[automatically_derived]
1182 impl #impl_generics ::object_rainbow::Parse<__I> for #target #ty_generics
1183 #where_clause
1184 {
1185 fn parse(mut input: __I) -> ::object_rainbow::Result<Self> {
1186 #parse
1187 }
1188 }
1189 };
1190 };
1191 TokenStream::from(output)
1192}
1193
1194#[derive(Debug, FromMeta)]
1195#[darling(derive_syn_parse)]
1196struct ParseArgs {
1197 bound: Option<Type>,
1198 #[darling(default)]
1199 unchecked: bool,
1200 with: Option<Expr>,
1201 #[darling(default, rename = "unstable_mutual")]
1202 mutual: bool,
1203}
1204
1205fn conditional_parse_name(f: &Field, inline: bool) -> Ident {
1206 let infix = if inline { "ParseInline" } else { "Parse" };
1207 let conditional = format!("__Conditional{infix}_{}", f.ident.as_ref().unwrap());
1208 Ident::new(&conditional, f.span())
1209}
1210
1211fn conditional_parse_input(inline: bool) -> proc_macro2::TokenStream {
1212 if inline {
1213 quote!(&mut impl ::object_rainbow::PointInput<Extra = Self::E>)
1214 } else {
1215 quote!(impl ::object_rainbow::PointInput<Extra = Self::E>)
1216 }
1217}
1218
1219fn conditional_parse_method(inline: bool) -> proc_macro2::TokenStream {
1220 if inline {
1221 quote!(parse_inline)
1222 } else {
1223 quote!(parse)
1224 }
1225}
1226
1227fn bounds_parse(
1228 mut generics: Generics,
1229 data: &Data,
1230 attrs: &[Attribute],
1231 name: &Ident,
1232 defs: &mut Vec<proc_macro2::TokenStream>,
1233) -> syn::Result<Generics> {
1234 let g_clone = generics.clone();
1235 let (impl_generics, ty_generics, where_clause) = g_clone.split_for_impl();
1236 let this = quote_spanned! { name.span() =>
1237 #name #ty_generics
1238 };
1239 let (recursive, _) = parse_recursive_inline(attrs)?;
1240 let tr = |last| match (last, recursive) {
1241 (true, true) => {
1242 quote!(::object_rainbow::Parse<__I> + ::object_rainbow::Object<__I::Extra>)
1243 }
1244 (true, false) => quote!(::object_rainbow::Parse<__I>),
1245 (false, true) => {
1246 quote!(::object_rainbow::ParseInline<__I> + ::object_rainbow::Inline<__I::Extra>)
1247 }
1248 (false, false) => quote!(::object_rainbow::ParseInline<__I>),
1249 };
1250 match data {
1251 Data::Struct(data) => {
1252 let last_at = data.fields.len().checked_sub(1).unwrap_or_default();
1253 'field: for (i, f) in data.fields.iter().enumerate() {
1254 let last = i == last_at;
1255 let ty = &f.ty;
1256 let mut b = None;
1257 for attr in &f.attrs {
1258 if attr_str(attr).as_deref() == Some("parse") {
1259 let ParseArgs {
1260 bound,
1261 unchecked,
1262 mutual,
1263 ..
1264 } = attr.parse_args::<ParseArgs>()?;
1265 if mutual {
1266 let conditional = conditional_parse_name(f, !last);
1267 let mut g_clone = g_clone.clone();
1268 g_clone.params.push(parse_quote!(
1269 __E: ::core::marker::Send + ::core::marker::Sync
1270 ));
1271 let (impl_generics_extra, _, _) = g_clone.split_for_impl();
1272 let input_type = conditional_parse_input(!last);
1273 let parse_method = conditional_parse_method(!last);
1274 defs.push(quote! {
1275 #[allow(non_camel_case_types)]
1276 trait #conditional #impl_generics: ::object_rainbow::BoundPair
1277 #where_clause
1278 {
1279 fn parse(
1280 input: #input_type,
1281 ) -> ::object_rainbow::Result<Self::T>
1282 where #this: ::object_rainbow::Object<Self::E>;
1283 }
1284
1285 impl #impl_generics_extra #conditional #ty_generics
1286 for (#ty, __E)
1287 #where_clause
1288 {
1289 fn parse(
1290 input: #input_type,
1291 ) -> ::object_rainbow::Result<Self::T>
1292 where #this: ::object_rainbow::Object<Self::E> {
1293 input.#parse_method::<Self::T>()
1294 }
1295 }
1296 });
1297 b = Some(parse_quote!(#conditional #ty_generics));
1298 }
1299 if unchecked {
1300 continue 'field;
1301 }
1302 if let Some(bound) = bound {
1303 b = Some(bound);
1304 }
1305 }
1306 }
1307 if let Some(bound) = b {
1308 generics.make_where_clause().predicates.push(
1309 parse_quote_spanned! { ty.span() =>
1310 (#ty, __I::Extra): ::object_rainbow::BoundPair<
1311 T = #ty, E = __I::Extra
1312 > + #bound
1313 },
1314 );
1315 } else {
1316 let tr = tr(last);
1317 generics.make_where_clause().predicates.push(
1318 parse_quote_spanned! { ty.span() =>
1319 #ty: #tr
1320 },
1321 );
1322 }
1323 }
1324 }
1325 Data::Enum(data) => {
1326 for v in data.variants.iter() {
1327 let last_at = v.fields.len().checked_sub(1).unwrap_or_default();
1328 'field: for (i, f) in v.fields.iter().enumerate() {
1329 let ty = &f.ty;
1330 let mut b = None;
1331 for attr in &f.attrs {
1332 if attr_str(attr).as_deref() == Some("parse") {
1333 let ParseArgs {
1334 bound, unchecked, ..
1335 } = attr.parse_args::<ParseArgs>()?;
1336 if unchecked {
1337 continue 'field;
1338 }
1339 if let Some(bound) = bound {
1340 b = Some(bound);
1341 }
1342 }
1343 }
1344 if let Some(bound) = b {
1345 generics.make_where_clause().predicates.push(
1346 parse_quote_spanned! { ty.span() =>
1347 (#ty, __I::Extra): ::object_rainbow::BoundPair<
1348 T = #ty, E = __I::Extra
1349 > + #bound
1350 },
1351 );
1352 } else {
1353 let last = i == last_at;
1354 let tr = tr(last);
1355 generics.make_where_clause().predicates.push(
1356 parse_quote_spanned! { ty.span() =>
1357 #ty: #tr
1358 },
1359 );
1360 }
1361 }
1362 }
1363 }
1364 Data::Union(data) => {
1365 return Err(Error::new_spanned(
1366 data.union_token,
1367 "`union`s are not supported",
1368 ));
1369 }
1370 }
1371 generics.params.push(if recursive {
1372 parse_quote!(__I: ::object_rainbow::PointInput<
1373 Extra: ::core::marker::Send + ::core::marker::Sync + ::core::clone::Clone
1374 >)
1375 } else {
1376 parse_quote!(__I: ::object_rainbow::ParseInput)
1377 });
1378 Ok(generics)
1379}
1380
1381fn gen_parse(data: &Data, ty_generics: &TypeGenerics<'_>) -> proc_macro2::TokenStream {
1382 match data {
1383 Data::Struct(data) => {
1384 let arm = fields_parse(&data.fields, ty_generics);
1385 quote! { Ok(Self #arm)}
1386 }
1387 Data::Enum(data) => {
1388 let parse = data.variants.iter().map(|v| {
1389 let ident = &v.ident;
1390 let arm = fields_parse(&v.fields, ty_generics);
1391 quote! {
1392 <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
1393 }
1394 });
1395 quote! {
1396 Ok(match input.parse_inline()? {
1397 #(#parse)*
1398 })
1399 }
1400 }
1401 Data::Union(data) => {
1402 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1403 }
1404 }
1405}
1406
1407fn fields_parse(fields: &syn::Fields, ty_generics: &TypeGenerics<'_>) -> proc_macro2::TokenStream {
1408 let last_at = fields.len().checked_sub(1).unwrap_or_default();
1409 match fields {
1410 syn::Fields::Named(fields) => {
1411 let parse = fields.named.iter().enumerate().map(|(i, f)| {
1412 let last = i == last_at;
1413 let ty = &f.ty;
1414 let mut w = None;
1415 let mut b = None;
1416 for attr in &f.attrs {
1417 if attr_str(attr).as_deref() == Some("parse") {
1418 let ParseArgs {
1419 with,
1420 bound,
1421 mutual,
1422 ..
1423 } = match attr.parse_args::<ParseArgs>() {
1424 Ok(args) => args,
1425 Err(e) => return e.into_compile_error(),
1426 };
1427 if mutual {
1428 let conditional = format!(
1429 "__Conditional{}_{}",
1430 if last { "Parse" } else { "ParseInline" },
1431 f.ident.as_ref().unwrap(),
1432 );
1433 let conditional = Ident::new(&conditional, f.span());
1434 w = Some(parse_quote!(parse));
1435 b = Some(parse_quote!(#conditional #ty_generics));
1436 }
1437 if let Some(with) = with {
1438 w = Some(with);
1439 }
1440 if let Some(bound) = bound {
1441 b = Some(bound);
1442 }
1443 }
1444 }
1445 let i = f.ident.as_ref().unwrap();
1446 if let Some(with) = w {
1447 let arg = if last {
1448 quote!(input)
1449 } else {
1450 quote!(&mut input)
1451 };
1452 if let Some(bound) = b {
1453 quote_spanned! { f.ty.span() =>
1454 #i: <(#ty, __I::Extra) as #bound>::#with(#arg)?
1455 }
1456 } else {
1457 quote_spanned! { f.ty.span() =>
1458 #i: #with(#arg)?
1459 }
1460 }
1461 } else {
1462 let method = if last {
1463 quote!(parse)
1464 } else {
1465 quote!(parse_inline)
1466 };
1467 quote_spanned! { f.ty.span() =>
1468 #i: input.#method()?
1469 }
1470 }
1471 });
1472 quote! { { #(#parse),* } }
1473 }
1474 syn::Fields::Unnamed(fields) => {
1475 let parse = fields.unnamed.iter().enumerate().map(|(i, f)| {
1476 let ty = &f.ty;
1477 let mut w = None;
1478 let mut b = None;
1479 for attr in &f.attrs {
1480 if attr_str(attr).as_deref() == Some("parse") {
1481 let ParseArgs { with, bound, .. } = match attr.parse_args::<ParseArgs>() {
1482 Ok(args) => args,
1483 Err(e) => return e.into_compile_error(),
1484 };
1485 if let Some(with) = with {
1486 w = Some(with);
1487 }
1488 if let Some(bound) = bound {
1489 b = Some(bound);
1490 }
1491 }
1492 }
1493 let last = i == last_at;
1494 if let Some(with) = w {
1495 let arg = if last {
1496 quote!(input)
1497 } else {
1498 quote!(&mut input)
1499 };
1500 if let Some(bound) = b {
1501 quote_spanned! { f.ty.span() =>
1502 <(#ty, __I::Extra) as #bound>::#with(#arg)?
1503 }
1504 } else {
1505 quote_spanned! { f.ty.span() =>
1506 #with(#arg)?
1507 }
1508 }
1509 } else {
1510 let method = if last {
1511 quote!(parse)
1512 } else {
1513 quote!(parse_inline)
1514 };
1515 quote_spanned! { f.ty.span() =>
1516 input.#method()?
1517 }
1518 }
1519 });
1520 quote! { (#(#parse),*) }
1521 }
1522 syn::Fields::Unit => quote! {},
1523 }
1524}
1525
1526#[proc_macro_derive(ParseInline, attributes(parse))]
1527pub fn derive_parse_inline(input: TokenStream) -> TokenStream {
1528 let input = parse_macro_input!(input as DeriveInput);
1529 let name = input.ident;
1530 let generics = input.generics.clone();
1531 let (_, ty_generics, _) = generics.split_for_impl();
1532 let generics = match bounds_parse_inline(input.generics, &input.data, &input.attrs) {
1533 Ok(g) => g,
1534 Err(e) => return e.into_compile_error().into(),
1535 };
1536 let parse_inline = gen_parse_inline(&input.data);
1537 let (impl_generics, _, where_clause) = generics.split_for_impl();
1538 let target = parse_for(&name, &input.attrs);
1539 let output = quote! {
1540 #[automatically_derived]
1541 impl #impl_generics ::object_rainbow::ParseInline<__I> for #target #ty_generics #where_clause {
1542 fn parse_inline(input: &mut __I) -> ::object_rainbow::Result<Self> {
1543 #parse_inline
1544 }
1545 }
1546 };
1547 TokenStream::from(output)
1548}
1549
1550fn bounds_parse_inline(
1551 mut generics: Generics,
1552 data: &Data,
1553 attrs: &[Attribute],
1554) -> syn::Result<Generics> {
1555 let (recursive, _) = parse_recursive_inline(attrs)?;
1556 let tr = if recursive {
1557 quote!(::object_rainbow::ParseInline<__I> + ::object_rainbow::Inline<__I::Extra>)
1558 } else {
1559 quote!(::object_rainbow::ParseInline<__I>)
1560 };
1561 match data {
1562 Data::Struct(data) => {
1563 'field: for f in data.fields.iter() {
1564 let ty = &f.ty;
1565 let mut b = None;
1566 for attr in &f.attrs {
1567 if attr_str(attr).as_deref() == Some("parse") {
1568 let ParseArgs {
1569 bound, unchecked, ..
1570 } = attr.parse_args::<ParseArgs>()?;
1571 if unchecked {
1572 continue 'field;
1573 }
1574 if let Some(bound) = bound {
1575 b = Some(bound);
1576 }
1577 }
1578 }
1579 if let Some(bound) = b {
1580 generics.make_where_clause().predicates.push(
1581 parse_quote_spanned! { ty.span() =>
1582 (#ty, __I::Extra): #bound
1583 },
1584 );
1585 } else {
1586 generics.make_where_clause().predicates.push(
1587 parse_quote_spanned! { ty.span() =>
1588 #ty: #tr
1589 },
1590 );
1591 }
1592 }
1593 }
1594 Data::Enum(data) => {
1595 for v in data.variants.iter() {
1596 'field: for f in v.fields.iter() {
1597 let ty = &f.ty;
1598 let mut b = None;
1599 for attr in &f.attrs {
1600 if attr_str(attr).as_deref() == Some("parse") {
1601 let ParseArgs {
1602 bound, unchecked, ..
1603 } = attr.parse_args::<ParseArgs>()?;
1604 if unchecked {
1605 continue 'field;
1606 }
1607 if let Some(bound) = bound {
1608 b = Some(bound);
1609 }
1610 }
1611 }
1612 if let Some(bound) = b {
1613 generics.make_where_clause().predicates.push(
1614 parse_quote_spanned! { ty.span() =>
1615 (#ty, __I::Extra): #bound
1616 },
1617 );
1618 } else {
1619 generics.make_where_clause().predicates.push(
1620 parse_quote_spanned! { ty.span() =>
1621 #ty: #tr
1622 },
1623 );
1624 }
1625 }
1626 }
1627 }
1628 Data::Union(data) => {
1629 return Err(Error::new_spanned(
1630 data.union_token,
1631 "`union`s are not supported",
1632 ));
1633 }
1634 }
1635 generics.params.push(if recursive {
1636 parse_quote!(__I: ::object_rainbow::PointInput<
1637 Extra: ::core::marker::Send + ::core::marker::Sync
1638 >)
1639 } else {
1640 parse_quote!(__I: ::object_rainbow::ParseInput)
1641 });
1642 Ok(generics)
1643}
1644
1645fn fields_parse_inline(fields: &syn::Fields) -> proc_macro2::TokenStream {
1646 match fields {
1647 syn::Fields::Named(fields) => {
1648 let parse = fields.named.iter().map(|f| {
1649 let i = f.ident.as_ref().unwrap();
1650 quote_spanned! { f.ty.span() =>
1651 #i: input.parse_inline()?
1652 }
1653 });
1654 quote! { { #(#parse),* } }
1655 }
1656 syn::Fields::Unnamed(fields) => {
1657 let parse = fields.unnamed.iter().map(|f| {
1658 quote_spanned! { f.ty.span() =>
1659 input.parse_inline()?
1660 }
1661 });
1662 quote! { (#(#parse),*) }
1663 }
1664 syn::Fields::Unit => quote! {},
1665 }
1666}
1667
1668fn gen_parse_inline(data: &Data) -> proc_macro2::TokenStream {
1669 match data {
1670 Data::Struct(data) => {
1671 let arm = fields_parse_inline(&data.fields);
1672 quote! { Ok(Self #arm) }
1673 }
1674 Data::Enum(data) => {
1675 let parse_inline = data.variants.iter().map(|v| {
1676 let ident = &v.ident;
1677 let arm = fields_parse_inline(&v.fields);
1678 quote! {
1679 <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
1680 }
1681 });
1682 quote! {
1683 Ok(match input.parse_inline()? {
1684 #(#parse_inline)*
1685 })
1686 }
1687 }
1688 Data::Union(data) => {
1689 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1690 }
1691 }
1692}
1693
1694#[proc_macro_derive(ParseAsInline)]
1695pub fn derive_parse_as_inline(input: TokenStream) -> TokenStream {
1696 let input = parse_macro_input!(input as DeriveInput);
1697 let name = input.ident;
1698 let generics = input.generics.clone();
1699 let (_, ty_generics, _) = generics.split_for_impl();
1700 let generics = match bounds_parse_as_inline(input.generics, &name) {
1701 Ok(g) => g,
1702 Err(e) => return e.into_compile_error().into(),
1703 };
1704 let (impl_generics, _, where_clause) = generics.split_for_impl();
1705 let target = parse_for(&name, &input.attrs);
1706 let output = quote! {
1707 #[automatically_derived]
1708 impl #impl_generics ::object_rainbow::Parse<__I> for #target #ty_generics #where_clause {
1709 fn parse(input: __I) -> ::object_rainbow::Result<Self> {
1710 ::object_rainbow::ParseInline::<__I>::parse_as_inline(input)
1711 }
1712 }
1713 };
1714 TokenStream::from(output)
1715}
1716
1717fn bounds_parse_as_inline(mut generics: Generics, name: &Ident) -> syn::Result<Generics> {
1718 generics
1719 .make_where_clause()
1720 .predicates
1721 .push(parse_quote_spanned! { name.span() =>
1722 Self: ::object_rainbow::ParseInline::<__I>
1723 });
1724 generics
1725 .params
1726 .push(parse_quote!(__I: ::object_rainbow::ParseInput));
1727 Ok(generics)
1728}
1729
1730fn parse_path(attr: &Attribute) -> syn::Result<Type> {
1731 attr.parse_args::<LitStr>()?.parse()
1732}
1733
1734fn attr_str(attr: &Attribute) -> Option<String> {
1735 Some(attr.path().get_ident()?.to_string())
1736}
1737
1738#[proc_macro_derive(Enum, attributes(enumtag))]
1739pub fn derive_enum(input: TokenStream) -> TokenStream {
1740 let input = parse_macro_input!(input as DeriveInput);
1741 let name = input.ident;
1742 let generics = input.generics.clone();
1743 let (_, ty_generics, _) = generics.split_for_impl();
1744 let generics = input.generics;
1745 let variants = gen_variants(&input.data);
1746 let variant_count = gen_variant_count(&input.data);
1747 let to_tag = gen_to_tag(&input.data);
1748 let from_tag = gen_from_tag(&input.data);
1749 let kind = gen_kind(&input.data);
1750 let (impl_generics, _, where_clause) = generics.split_for_impl();
1751 let mut errors = Vec::new();
1752 let mut enumtag = None;
1753 for attr in &input.attrs {
1754 if attr_str(attr).as_deref() == Some("enumtag") {
1755 match parse_path(attr) {
1756 Ok(path) => {
1757 if enumtag.is_some() {
1758 errors.push(Error::new_spanned(path, "duplicate tag"));
1759 } else {
1760 enumtag = Some(path);
1761 }
1762 }
1763 Err(e) => errors.push(e),
1764 }
1765 }
1766 }
1767 let enumtag = enumtag
1768 .unwrap_or_else(|| parse_quote!(::object_rainbow::numeric::Le<::core::num::NonZero<u8>>));
1769 let errors = errors.into_iter().map(|e| e.into_compile_error());
1770 let target = parse_for(&name, &input.attrs);
1771 let output = quote! {
1772 const _: () = {
1773 #(#errors)*
1774
1775 use ::object_rainbow::enumkind::EnumKind;
1776
1777 #[derive(Clone, Copy, ::object_rainbow::ParseAsInline)]
1778 pub enum __Kind {
1779 #variants
1780 }
1781
1782 #[automatically_derived]
1783 impl ::object_rainbow::enumkind::EnumKind for __Kind {
1784 type Tag = ::object_rainbow::enumkind::EnumTag<
1785 #enumtag,
1786 #variant_count,
1787 >;
1788
1789 fn to_tag(self) -> Self::Tag {
1790 #to_tag
1791 }
1792
1793 fn from_tag(tag: Self::Tag) -> Self {
1794 #from_tag
1795 }
1796 }
1797
1798 impl<I: ::object_rainbow::ParseInput> ::object_rainbow::ParseInline<I> for __Kind {
1799 fn parse_inline(input: &mut I) -> ::object_rainbow::Result<Self> {
1800 Ok(::object_rainbow::enumkind::EnumKind::from_tag(input.parse_inline()?))
1801 }
1802 }
1803
1804 #[automatically_derived]
1805 impl #impl_generics ::object_rainbow::Enum for #target #ty_generics #where_clause {
1806 type Kind = __Kind;
1807
1808 fn kind(&self) -> Self::Kind {
1809 #kind
1810 }
1811 }
1812 };
1813 };
1814 TokenStream::from(output)
1815}
1816
1817fn gen_variants(data: &Data) -> proc_macro2::TokenStream {
1818 match data {
1819 Data::Struct(data) => {
1820 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1821 }
1822 Data::Enum(data) => {
1823 let variants = data.variants.iter().map(|v| &v.ident);
1824 quote! { #(#variants),* }
1825 }
1826 Data::Union(data) => {
1827 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1828 }
1829 }
1830}
1831
1832fn gen_variant_count(data: &Data) -> proc_macro2::TokenStream {
1833 match data {
1834 Data::Struct(data) => {
1835 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1836 }
1837 Data::Enum(data) => {
1838 let variant_count = data.variants.len();
1839 quote! { #variant_count }
1840 }
1841 Data::Union(data) => {
1842 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1843 }
1844 }
1845}
1846
1847fn gen_to_tag(data: &Data) -> proc_macro2::TokenStream {
1848 match data {
1849 Data::Struct(data) => {
1850 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1851 }
1852 Data::Enum(data) => {
1853 let to_tag = data.variants.iter().enumerate().map(|(i, v)| {
1854 let ident = &v.ident;
1855 quote_spanned! { ident.span() =>
1856 Self::#ident => ::object_rainbow::enumkind::EnumTag::from_const::<#i>(),
1857 }
1858 });
1859 quote! {
1860 match self {
1861 #(#to_tag)*
1862 }
1863 }
1864 }
1865 Data::Union(data) => {
1866 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1867 }
1868 }
1869}
1870
1871fn gen_from_tag(data: &Data) -> proc_macro2::TokenStream {
1872 match data {
1873 Data::Struct(data) => {
1874 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1875 }
1876 Data::Enum(data) => {
1877 let from_tag = data.variants.iter().enumerate().map(|(i, v)| {
1878 let ident = &v.ident;
1879 quote_spanned! { ident.span() =>
1880 #i => Self::#ident,
1881 }
1882 });
1883 quote! {
1884 match tag.to_usize() {
1885 #(#from_tag)*
1886 _ => unreachable!(),
1887 }
1888 }
1889 }
1890 Data::Union(data) => {
1891 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1892 }
1893 }
1894}
1895
1896fn gen_kind(data: &Data) -> proc_macro2::TokenStream {
1897 match data {
1898 Data::Struct(data) => {
1899 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
1900 }
1901 Data::Enum(data) => {
1902 let variants = data.variants.iter().map(|v| {
1903 let ident = &v.ident;
1904 quote_spanned! { ident.span() =>
1905 Self::#ident {..} => __Kind::#ident,
1906 }
1907 });
1908 quote! {
1909 match self {
1910 #(#variants)*
1911 }
1912 }
1913 }
1914 Data::Union(data) => {
1915 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1916 }
1917 }
1918}
1919
1920#[proc_macro_derive(MaybeHasNiche)]
1921pub fn derive_maybe_has_niche(input: TokenStream) -> TokenStream {
1922 let input = parse_macro_input!(input as DeriveInput);
1923 let name = input.ident;
1924 let mn_array = gen_mn_array(&input.data);
1925 let (_, ty_generics, _) = input.generics.split_for_impl();
1926 let generics = match bounds_maybe_has_niche(input.generics.clone(), &input.data) {
1927 Ok(g) => g,
1928 Err(e) => return e.into_compile_error().into(),
1929 };
1930 let (impl_generics, _, where_clause) = generics.split_for_impl();
1931 let target = parse_for(&name, &input.attrs);
1932 let output = quote! {
1933 const _: () = {
1934 use ::object_rainbow::typenum::tarr;
1935
1936 #[automatically_derived]
1937 impl #impl_generics ::object_rainbow::MaybeHasNiche for #target #ty_generics #where_clause {
1938 type MnArray = #mn_array;
1939 }
1940 };
1941 };
1942 TokenStream::from(output)
1943}
1944
1945fn bounds_maybe_has_niche(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
1946 match data {
1947 Data::Struct(data) => {
1948 for f in data.fields.iter() {
1949 let ty = &f.ty;
1950 generics
1951 .make_where_clause()
1952 .predicates
1953 .push(parse_quote_spanned! { ty.span() =>
1954 #ty: ::object_rainbow::MaybeHasNiche<
1955 MnArray: ::object_rainbow::MnArray<
1956 MaybeNiche: ::object_rainbow::MaybeNiche
1957 >
1958 >
1959 });
1960 }
1961 }
1962 Data::Enum(data) => {
1963 generics.params.push(parse_quote!(
1964 __N: ::object_rainbow::typenum::Unsigned
1965 ));
1966 for (i, v) in data.variants.iter().enumerate() {
1967 let mn_array = fields_mn_array(&v.fields, Some(i));
1968 generics
1969 .make_where_clause()
1970 .predicates
1971 .push(parse_quote_spanned! { v.span() =>
1972 #mn_array: ::object_rainbow::MnArray<
1973 MaybeNiche: ::object_rainbow::NicheOr<N = __N>
1974 >
1975 });
1976 for f in v.fields.iter() {
1977 let ty = &f.ty;
1978 generics.make_where_clause().predicates.push(
1979 parse_quote_spanned! { ty.span() =>
1980 #ty: ::object_rainbow::MaybeHasNiche<
1981 MnArray: ::object_rainbow::MnArray<
1982 MaybeNiche: ::object_rainbow::MaybeNiche
1983 >
1984 >
1985 },
1986 );
1987 }
1988 }
1989 }
1990 Data::Union(data) => {
1991 return Err(Error::new_spanned(
1992 data.union_token,
1993 "`union`s are not supported",
1994 ));
1995 }
1996 }
1997 Ok(generics)
1998}
1999
2000fn fields_mn_array(fields: &syn::Fields, variant: Option<usize>) -> proc_macro2::TokenStream {
2001 let mn_array = fields.iter().map(|f| {
2002 let ty = &f.ty;
2003 quote! {
2004 <
2005 <
2006 #ty
2007 as
2008 ::object_rainbow::MaybeHasNiche
2009 >::MnArray
2010 as
2011 ::object_rainbow::MnArray
2012 >::MaybeNiche
2013 }
2014 });
2015 if let Some(variant) = variant {
2016 let kind_niche = quote! {
2017 ::object_rainbow::AutoEnumNiche<Self, #variant>
2018 };
2019 quote! { tarr![#kind_niche, ::object_rainbow::NoNiche<::object_rainbow::HackNiche<#variant>>, #(#mn_array),*] }
2020 } else {
2021 quote! { tarr![#(#mn_array),*] }
2022 }
2023}
2024
2025fn gen_mn_array(data: &Data) -> proc_macro2::TokenStream {
2026 match data {
2027 Data::Struct(data) => fields_mn_array(&data.fields, None),
2028 Data::Enum(data) => {
2029 let mn_array = data.variants.iter().enumerate().map(|(i, v)| {
2030 let mn_array = fields_mn_array(&v.fields, Some(i));
2031 quote! { <#mn_array as ::object_rainbow::MnArray>::MaybeNiche }
2032 });
2033 quote! {
2034 ::object_rainbow::NicheFoldOrArray<tarr![#(#mn_array),*]>
2035 }
2036 }
2037 Data::Union(data) => {
2038 Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
2039 }
2040 }
2041}