1use std::collections::BTreeSet;
4
5use darling::FromMeta;
6use proc_macro::TokenStream;
7use quote::{ToTokens, quote, quote_spanned};
8use syn::{
9 Attribute, Data, DeriveInput, Error, Expr, Field, FnArg, GenericParam, Generics, Ident,
10 ImplItem, ItemTrait, LitStr, Path, TraitItem, Type, TypeGenerics, parse::Parse,
11 parse_macro_input, parse_quote, parse_quote_spanned, spanned::Spanned, token::Comma,
12};
13
14use self::contains_generics::{GContext, type_contains_generics};
15
16mod contains_generics;
17
18fn bounds_g(generics: &Generics) -> BTreeSet<Ident> {
19 generics
20 .params
21 .iter()
22 .filter_map(|param| match param {
23 GenericParam::Lifetime(_) => None,
24 GenericParam::Type(param) => Some(¶m.ident),
25 GenericParam::Const(param) => Some(¶m.ident),
26 })
27 .cloned()
28 .collect()
29}
30
31#[derive(Debug, FromMeta)]
32#[darling(derive_syn_parse)]
33struct RainbowArgs {
34 #[darling(default)]
35 remote: Option<Type>,
36}
37
38fn parse_for(name: &Ident, attrs: &[Attribute]) -> proc_macro2::TokenStream {
39 for attr in attrs {
40 if attr_str(attr).as_deref() == Some("rainbow") {
41 match attr.parse_args::<RainbowArgs>() {
42 Ok(RainbowArgs { remote }) => {
43 if let Some(remote) = remote {
44 return remote.to_token_stream();
45 }
46 }
47 Err(e) => return e.into_compile_error(),
48 }
49 }
50 }
51 name.to_token_stream()
52}
53
54#[proc_macro_derive(ToOutput, attributes(rainbow))]
74pub fn derive_to_output(input: TokenStream) -> TokenStream {
75 let input = parse_macro_input!(input as DeriveInput);
76 let name = input.ident;
77 let generics = match bounds_to_output(input.generics, &input.data) {
78 Ok(g) => g,
79 Err(e) => return e.into_compile_error().into(),
80 };
81 let to_output = gen_to_output(&input.data);
82 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
83 let target = parse_for(&name, &input.attrs);
84 let output = quote! {
85 #[automatically_derived]
86 impl #impl_generics ::object_rainbow::ToOutput for #target #ty_generics #where_clause {
87 fn to_output(&self, output: &mut dyn ::object_rainbow::Output) {
88 #to_output
89 }
90 }
91 };
92 TokenStream::from(output)
93}
94
95fn bounds_to_output(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
96 let g = &bounds_g(&generics);
97 match data {
98 Data::Struct(data) => {
99 let last_at = data.fields.len().saturating_sub(1);
100 for (i, f) in data.fields.iter().enumerate() {
101 let last = i == last_at;
102 let ty = &f.ty;
103 let tr = if last {
104 quote!(::object_rainbow::ToOutput)
105 } else {
106 quote!(::object_rainbow::InlineOutput)
107 };
108 if !last || type_contains_generics(GContext { g, always: false }, ty) {
109 generics.make_where_clause().predicates.push(
110 parse_quote_spanned! { ty.span() =>
111 #ty: #tr
112 },
113 );
114 }
115 }
116 }
117 Data::Enum(data) => {
118 for v in data.variants.iter() {
119 let last_at = v.fields.len().saturating_sub(1);
120 for (i, f) in v.fields.iter().enumerate() {
121 let last = i == last_at;
122 let ty = &f.ty;
123 let tr = if last {
124 quote!(::object_rainbow::ToOutput)
125 } else {
126 quote!(::object_rainbow::InlineOutput)
127 };
128 if !last || type_contains_generics(GContext { g, always: false }, ty) {
129 generics.make_where_clause().predicates.push(
130 parse_quote_spanned! { ty.span() =>
131 #ty: #tr
132 },
133 );
134 }
135 }
136 }
137 }
138 Data::Union(data) => {
139 return Err(Error::new_spanned(
140 data.union_token,
141 "`union`s are not supported",
142 ));
143 }
144 }
145 Ok(generics)
146}
147
148fn fields_to_output(fields: &syn::Fields) -> proc_macro2::TokenStream {
149 match fields {
150 syn::Fields::Named(fields) => {
151 let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
152 let to_output = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
153 quote_spanned! { f.ty.span() =>
154 #i.to_output(output)
155 }
156 });
157 quote! {
158 { #(#let_self),* } => {
159 #(#to_output);*
160 }
161 }
162 }
163 syn::Fields::Unnamed(fields) => {
164 let let_self = fields
165 .unnamed
166 .iter()
167 .enumerate()
168 .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
169 let to_output = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
170 quote_spanned! { f.ty.span() =>
171 #i.to_output(output)
172 }
173 });
174 quote! {
175 (#(#let_self),*) => {
176 #(#to_output);*
177 }
178 }
179 }
180 syn::Fields::Unit => quote! {
181 => {}
182 },
183 }
184}
185
186fn gen_to_output(data: &Data) -> proc_macro2::TokenStream {
187 match data {
188 Data::Struct(data) => {
189 let arm = fields_to_output(&data.fields);
190 quote! {
191 match self {
192 Self #arm
193 }
194 }
195 }
196 Data::Enum(data) => {
197 let to_output = data.variants.iter().map(|v| {
198 let ident = &v.ident;
199 let arm = fields_to_output(&v.fields);
200 quote! { Self::#ident #arm }
201 });
202 quote! {
203 let kind = ::object_rainbow::Enum::kind(self);
204 let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
205 tag.to_output(output);
206 match self {
207 #(#to_output)*
208 }
209 }
210 }
211 Data::Union(data) => {
212 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
213 }
214 }
215}
216
217#[proc_macro_derive(InlineOutput)]
237pub fn derive_inline_output(input: TokenStream) -> TokenStream {
238 let input = parse_macro_input!(input as DeriveInput);
239 let name = input.ident;
240 let generics = match bounds_inline_output(input.generics, &input.data) {
241 Ok(g) => g,
242 Err(e) => return e.into_compile_error().into(),
243 };
244 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
245 let target = parse_for(&name, &input.attrs);
246 let output = quote! {
247 #[automatically_derived]
248 impl #impl_generics ::object_rainbow::InlineOutput for #target #ty_generics #where_clause {}
249 };
250 TokenStream::from(output)
251}
252
253fn bounds_inline_output(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
254 match data {
255 Data::Struct(data) => {
256 for f in data.fields.iter() {
257 let ty = &f.ty;
258 generics
259 .make_where_clause()
260 .predicates
261 .push(parse_quote_spanned! { ty.span() =>
262 #ty: ::object_rainbow::InlineOutput
263 });
264 }
265 }
266 Data::Enum(data) => {
267 for v in data.variants.iter() {
268 for f in v.fields.iter() {
269 let ty = &f.ty;
270 generics.make_where_clause().predicates.push(
271 parse_quote_spanned! { ty.span() =>
272 #ty: ::object_rainbow::InlineOutput
273 },
274 );
275 }
276 }
277 }
278 Data::Union(data) => {
279 return Err(Error::new_spanned(
280 data.union_token,
281 "`union`s are not supported",
282 ));
283 }
284 }
285 Ok(generics)
286}
287
288#[proc_macro_derive(ListHashes, attributes(topology))]
308pub fn derive_list_hashes(input: TokenStream) -> TokenStream {
309 let input = parse_macro_input!(input as DeriveInput);
310 let name = input.ident;
311 let generics = input.generics.clone();
312 let (_, ty_generics, _) = generics.split_for_impl();
313 let generics = match bounds_list_hashes(input.generics, &input.data) {
314 Ok(g) => g,
315 Err(e) => return e.into_compile_error().into(),
316 };
317 let list_hashes = gen_list_hashes(&input.data);
318 let (impl_generics, _, where_clause) = generics.split_for_impl();
319 let target = parse_for(&name, &input.attrs);
320 let output = quote! {
321 #[automatically_derived]
322 impl #impl_generics ::object_rainbow::ListHashes for #target #ty_generics #where_clause {
323 fn list_hashes(&self, visitor: &mut impl FnMut(::object_rainbow::Hash)) {
324 #list_hashes
325 }
326 }
327 };
328 TokenStream::from(output)
329}
330
331fn bounds_list_hashes(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
332 let g = &bounds_g(&generics);
333 match data {
334 Data::Struct(data) => {
335 for f in data.fields.iter() {
336 let ty = &f.ty;
337 if type_contains_generics(GContext { g, always: false }, ty) {
338 generics.make_where_clause().predicates.push(
339 parse_quote_spanned! { ty.span() =>
340 #ty: ::object_rainbow::ListHashes
341 },
342 );
343 }
344 }
345 }
346 Data::Enum(data) => {
347 for v in data.variants.iter() {
348 for f in v.fields.iter() {
349 let ty = &f.ty;
350 if type_contains_generics(GContext { g, always: false }, ty) {
351 generics.make_where_clause().predicates.push(
352 parse_quote_spanned! { ty.span() =>
353 #ty: ::object_rainbow::ListHashes
354 },
355 );
356 }
357 }
358 }
359 }
360 Data::Union(data) => {
361 return Err(Error::new_spanned(
362 data.union_token,
363 "`union`s are not supported",
364 ));
365 }
366 }
367 Ok(generics)
368}
369
370fn fields_list_hashes(fields: &syn::Fields) -> proc_macro2::TokenStream {
371 match fields {
372 syn::Fields::Named(fields) => {
373 let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
374 let list_hashes = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
375 quote_spanned! { f.ty.span() =>
376 #i.list_hashes(visitor)
377 }
378 });
379 quote! {
380 { #(#let_self),* } => {
381 #(#list_hashes);*
382 }
383 }
384 }
385 syn::Fields::Unnamed(fields) => {
386 let let_self = fields
387 .unnamed
388 .iter()
389 .enumerate()
390 .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
391 let list_hashes = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
392 quote_spanned! { f.ty.span() =>
393 #i.list_hashes(visitor)
394 }
395 });
396 quote! {
397 (#(#let_self),*) => {
398 #(#list_hashes);*
399 }
400 }
401 }
402 syn::Fields::Unit => quote! {
403 => {}
404 },
405 }
406}
407
408fn gen_list_hashes(data: &Data) -> proc_macro2::TokenStream {
409 match data {
410 Data::Struct(data) => {
411 let arm = fields_list_hashes(&data.fields);
412 quote! {
413 match self {
414 Self #arm
415 }
416 }
417 }
418 Data::Enum(data) => {
419 let to_output = data.variants.iter().map(|v| {
420 let ident = &v.ident;
421 let arm = fields_list_hashes(&v.fields);
422 quote! { Self::#ident #arm }
423 });
424 quote! {
425 let kind = ::object_rainbow::Enum::kind(self);
426 let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
427 tag.list_hashes(visitor);
428 match self {
429 #(#to_output)*
430 }
431 }
432 }
433 Data::Union(data) => {
434 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
435 }
436 }
437}
438
439#[proc_macro_derive(Topological, attributes(topology))]
459pub fn derive_topological(input: TokenStream) -> TokenStream {
460 let input = parse_macro_input!(input as DeriveInput);
461 let name = input.ident;
462 let generics = input.generics.clone();
463 let (_, ty_generics, _) = generics.split_for_impl();
464 let mut defs = Vec::new();
465 let generics =
466 match bounds_topological(input.generics, &input.data, &input.attrs, &name, &mut defs) {
467 Ok(g) => g,
468 Err(e) => return e.into_compile_error().into(),
469 };
470 let traverse = gen_traverse(&input.data, &ty_generics);
471 let (impl_generics, _, where_clause) = generics.split_for_impl();
472 let target = parse_for(&name, &input.attrs);
473 let output = quote! {
474 const _: () = {
475 #(#defs)*
476
477 #[automatically_derived]
478 impl #impl_generics ::object_rainbow::Topological for #target #ty_generics
479 #where_clause
480 {
481 fn traverse(&self, visitor: &mut impl ::object_rainbow::PointVisitor) {
482 #traverse
483 }
484 }
485 };
486 };
487 TokenStream::from(output)
488}
489
490#[derive(Debug, FromMeta)]
491#[darling(derive_syn_parse)]
492struct ContainerTopologyArgs {
493 #[darling(default)]
494 recursive: bool,
495 #[darling(default)]
496 inline: bool,
497}
498
499fn parse_recursive_inline(attrs: &[Attribute]) -> syn::Result<(bool, bool)> {
500 let mut r = false;
501 let mut i = false;
502 for attr in attrs {
503 if attr_str(attr).as_deref() == Some("topology") {
504 let ContainerTopologyArgs { recursive, inline } = attr.parse_args()?;
505 if recursive {
506 r = true;
507 }
508 if inline {
509 i = true;
510 }
511 }
512 }
513 Ok((r, i))
514}
515
516#[derive(Debug, FromMeta)]
517#[darling(derive_syn_parse)]
518struct FieldTopologyArgs {
519 bound: Option<Path>,
520 #[darling(default)]
521 unchecked: bool,
522 with: Option<Expr>,
523 #[darling(default, rename = "unstable_mutual")]
524 mutual: bool,
525}
526
527fn bounds_topological(
528 mut generics: Generics,
529 data: &Data,
530 attrs: &[Attribute],
531 name: &Ident,
532 defs: &mut Vec<proc_macro2::TokenStream>,
533) -> syn::Result<Generics> {
534 let (recursive, inline) = parse_recursive_inline(attrs)?;
535 let g = &bounds_g(&generics);
536 let g_clone = generics.clone();
537 let (impl_generics, ty_generics, where_clause) = g_clone.split_for_impl();
538 let this = quote_spanned! { name.span() =>
539 #name #ty_generics
540 };
541 let bound = if recursive {
542 quote! { ::object_rainbow::Traversible }
543 } else {
544 quote! { ::object_rainbow::Topological }
545 };
546 match data {
547 Data::Struct(data) => {
548 'field: for f in data.fields.iter() {
549 let ty = &f.ty;
550 let mut b = None;
551 for attr in &f.attrs {
552 if attr_str(attr).as_deref() == Some("topology") {
553 let FieldTopologyArgs {
554 bound,
555 unchecked,
556 mutual,
557 ..
558 } = attr.parse_args()?;
559 if mutual {
560 let conditional =
561 format!("__ConditionalTopology_{}", f.ident.as_ref().unwrap());
562 let conditional = Ident::new(&conditional, f.span());
563 defs.push(quote! {
564 #[allow(non_camel_case_types)]
565 trait #conditional #impl_generics #where_clause {
566 fn traverse(
567 &self, visitor: &mut impl ::object_rainbow::PointVisitor,
568 ) where #this: ::object_rainbow::Traversible;
569 }
570
571 impl #impl_generics #conditional #ty_generics for #ty
572 #where_clause
573 {
574 fn traverse(
575 &self, visitor: &mut impl ::object_rainbow::PointVisitor,
576 ) where #this: ::object_rainbow::Traversible {
577 ::object_rainbow::Topological::traverse(self, visitor)
578 }
579 }
580 });
581 b = Some(parse_quote!(#conditional #ty_generics));
582 }
583 if unchecked {
584 continue 'field;
585 }
586 if let Some(bound) = bound {
587 b = Some(bound);
588 }
589 }
590 }
591 let bound = if let Some(bound) = b {
592 quote! { #bound }
593 } else {
594 bound.clone()
595 };
596 if type_contains_generics(GContext { g, always: false }, ty) {
597 generics.make_where_clause().predicates.push(
598 parse_quote_spanned! { ty.span() =>
599 #ty: #bound
600 },
601 );
602 }
603 }
604 }
605 Data::Enum(data) => {
606 for v in data.variants.iter() {
607 'field: for (i, f) in v.fields.iter().enumerate() {
608 let ty = &f.ty;
609 let mut b = None;
610 for attr in &f.attrs {
611 if attr_str(attr).as_deref() == Some("topology") {
612 let FieldTopologyArgs {
613 bound,
614 unchecked,
615 mutual,
616 ..
617 } = attr.parse_args()?;
618 if mutual {
619 let conditional = format!("__ConditionalTopology_{i}");
620 let conditional = Ident::new(&conditional, f.span());
621 defs.push(quote! {
622 #[allow(non_camel_case_types)]
623 trait #conditional #impl_generics #where_clause {
624 fn traverse(
625 &self, visitor: &mut impl ::object_rainbow::PointVisitor,
626 ) where #this: ::object_rainbow::Traversible;
627 }
628
629 impl #impl_generics #conditional #ty_generics for #ty
630 #where_clause
631 {
632 fn traverse(
633 &self, visitor: &mut impl ::object_rainbow::PointVisitor,
634 ) where #this: ::object_rainbow::Traversible {
635 ::object_rainbow::Topological::traverse(self, visitor)
636 }
637 }
638 });
639 }
640 if unchecked {
641 continue 'field;
642 }
643 if let Some(bound) = bound {
644 b = Some(bound);
645 }
646 }
647 }
648 let bound = if let Some(bound) = b {
649 quote! { #bound }
650 } else {
651 bound.clone()
652 };
653 if type_contains_generics(GContext { g, always: false }, ty) {
654 generics.make_where_clause().predicates.push(
655 parse_quote_spanned! { ty.span() =>
656 #ty: #bound
657 },
658 );
659 }
660 }
661 }
662 }
663 Data::Union(data) => {
664 return Err(Error::new_spanned(
665 data.union_token,
666 "`union`s are not supported",
667 ));
668 }
669 }
670 let output_bound = if inline {
671 quote! {
672 ::object_rainbow::InlineOutput
673 }
674 } else {
675 quote! {
676 ::object_rainbow::ToOutput
677 }
678 };
679 if recursive {
680 generics
681 .make_where_clause()
682 .predicates
683 .push(parse_quote_spanned! { name.span() =>
684 Self: #output_bound + ::object_rainbow::Tagged
685 });
686 }
687 Ok(generics)
688}
689
690fn fields_traverse(
691 fields: &syn::Fields,
692 ty_generics: &TypeGenerics<'_>,
693) -> proc_macro2::TokenStream {
694 match fields {
695 syn::Fields::Named(fields) => {
696 let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
697 let traverse = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
698 let ty = &f.ty;
699 let mut w = None;
700 let mut b = None;
701 for attr in &f.attrs {
702 if attr_str(attr).as_deref() == Some("topology") {
703 let FieldTopologyArgs {
704 with,
705 bound,
706 mutual,
707 ..
708 } = match attr.parse_args() {
709 Ok(args) => args,
710 Err(e) => return e.into_compile_error(),
711 };
712 if mutual {
713 let conditional = format!("__ConditionalTopology_{i}");
714 let conditional = Ident::new(&conditional, f.span());
715 w = Some(parse_quote!(traverse));
716 b = Some(parse_quote!(#conditional #ty_generics));
717 }
718 if let Some(with) = with {
719 w = Some(with);
720 }
721 if let Some(bound) = bound {
722 b = Some(bound);
723 }
724 }
725 }
726 if let Some(with) = w {
727 if let Some(bound) = b {
728 quote_spanned! { f.ty.span() =>
729 <#ty as #bound>::#with(#i, visitor)
730 }
731 } else {
732 quote_spanned! { f.ty.span() =>
733 #with(#i, visitor)
734 }
735 }
736 } else {
737 quote_spanned! { f.ty.span() =>
738 #i.traverse(visitor)
739 }
740 }
741 });
742 quote! {
743 { #(#let_self),* } => {
744 #(#traverse);*
745 }
746 }
747 }
748 syn::Fields::Unnamed(fields) => {
749 let let_self = fields
750 .unnamed
751 .iter()
752 .enumerate()
753 .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
754 let traverse = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
755 let ty = &f.ty;
756 let mut w = None;
757 let mut b = None;
758 for attr in &f.attrs {
759 if attr_str(attr).as_deref() == Some("topology") {
760 let FieldTopologyArgs {
761 with,
762 bound,
763 mutual,
764 ..
765 } = match attr.parse_args() {
766 Ok(args) => args,
767 Err(e) => return e.into_compile_error(),
768 };
769 if mutual {
770 let conditional = format!("__ConditionalTopology_{i}");
771 let conditional = Ident::new(&conditional, f.span());
772 w = Some(parse_quote!(traverse));
773 b = Some(parse_quote!(#conditional #ty_generics));
774 }
775 if let Some(with) = with {
776 w = Some(with);
777 }
778 if let Some(bound) = bound {
779 b = Some(bound);
780 }
781 }
782 }
783 if let Some(with) = w {
784 if let Some(bound) = b {
785 quote_spanned! { f.ty.span() =>
786 <#ty as #bound>::#with(#i, visitor)
787 }
788 } else {
789 quote_spanned! { f.ty.span() =>
790 #with(#i, visitor)
791 }
792 }
793 } else {
794 quote_spanned! { f.ty.span() =>
795 #i.traverse(visitor)
796 }
797 }
798 });
799 quote! {
800 (#(#let_self),*) => {
801 #(#traverse);*
802 }
803 }
804 }
805 syn::Fields::Unit => quote! {
806 => {}
807 },
808 }
809}
810
811fn gen_traverse(data: &Data, ty_generics: &TypeGenerics<'_>) -> proc_macro2::TokenStream {
812 match data {
813 Data::Struct(data) => {
814 let arm = fields_traverse(&data.fields, ty_generics);
815 quote! {
816 match self {
817 Self #arm
818 }
819 }
820 }
821 Data::Enum(data) => {
822 let to_output = data.variants.iter().map(|v| {
823 let ident = &v.ident;
824 let arm = fields_traverse(&v.fields, ty_generics);
825 quote! { Self::#ident #arm }
826 });
827 quote! {
828 let kind = ::object_rainbow::Enum::kind(self);
829 let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
830 tag.traverse(visitor);
831 match self {
832 #(#to_output)*
833 }
834 }
835 }
836 Data::Union(data) => {
837 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
838 }
839 }
840}
841
842#[proc_macro_derive(Tagged, attributes(tags))]
862pub fn derive_tagged(input: TokenStream) -> TokenStream {
863 let input = parse_macro_input!(input as DeriveInput);
864 let name = input.ident;
865 let mut errors = Vec::new();
866 let generics = match bounds_tagged(input.generics, &input.data, &mut errors) {
867 Ok(g) => g,
868 Err(e) => return e.into_compile_error().into(),
869 };
870 let tags = gen_tags(&input.data, &input.attrs, &mut errors);
871 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
872 let errors = errors.into_iter().map(|e| e.into_compile_error());
873 let target = parse_for(&name, &input.attrs);
874 let output = quote! {
875 #(#errors)*
876
877 #[automatically_derived]
878 impl #impl_generics ::object_rainbow::Tagged for #target #ty_generics #where_clause {
879 const TAGS: ::object_rainbow::Tags = #tags;
880 }
881 };
882 TokenStream::from(output)
883}
884
885struct FieldTagArgs {
886 skip: bool,
887}
888
889impl Parse for FieldTagArgs {
890 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
891 let mut skip = false;
892 while !input.is_empty() {
893 let ident = input.parse::<Ident>()?;
894 if ident.to_string().as_str() != "skip" {
895 return Err(Error::new(ident.span(), "expected: skip"));
896 }
897 skip = true;
898 if !input.is_empty() {
899 input.parse::<Comma>()?;
900 }
901 }
902 Ok(Self { skip })
903 }
904}
905
906fn bounds_tagged(
907 mut generics: Generics,
908 data: &Data,
909 errors: &mut Vec<Error>,
910) -> syn::Result<Generics> {
911 let g = &bounds_g(&generics);
912 match data {
913 Data::Struct(data) => {
914 for f in data.fields.iter() {
915 let mut skip = false;
916 for attr in &f.attrs {
917 if attr_str(attr).as_deref() == Some("tags") {
918 match attr.parse_args::<FieldTagArgs>() {
919 Ok(args) => skip |= args.skip,
920 Err(e) => errors.push(e),
921 }
922 }
923 }
924 if !skip {
925 let ty = &f.ty;
926 if type_contains_generics(GContext { g, always: false }, ty) {
927 generics.make_where_clause().predicates.push(
928 parse_quote_spanned! { ty.span() =>
929 #ty: ::object_rainbow::Tagged
930 },
931 );
932 }
933 }
934 }
935 }
936 Data::Enum(data) => {
937 for v in data.variants.iter() {
938 for f in v.fields.iter() {
939 let mut skip = false;
940 for attr in &f.attrs {
941 if attr_str(attr).as_deref() == Some("tags") {
942 match attr.parse_args::<FieldTagArgs>() {
943 Ok(args) => skip |= args.skip,
944 Err(e) => errors.push(e),
945 }
946 }
947 }
948 if !skip {
949 let ty = &f.ty;
950 if type_contains_generics(GContext { g, always: false }, ty) {
951 generics.make_where_clause().predicates.push(
952 parse_quote_spanned! { ty.span() =>
953 #ty: ::object_rainbow::Tagged
954 },
955 );
956 }
957 }
958 }
959 }
960 }
961 Data::Union(data) => {
962 return Err(Error::new_spanned(
963 data.union_token,
964 "`union`s are not supported",
965 ));
966 }
967 }
968 Ok(generics)
969}
970
971struct StructTagArgs {
972 tags: Vec<LitStr>,
973}
974
975impl Parse for StructTagArgs {
976 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
977 let mut tags = Vec::new();
978 while !input.is_empty() {
979 let tag = input.parse::<LitStr>()?;
980 tags.push(tag);
981 if !input.is_empty() {
982 input.parse::<Comma>()?;
983 }
984 }
985 Ok(Self { tags })
986 }
987}
988
989fn fields_tags(fields: &syn::Fields) -> Vec<proc_macro2::TokenStream> {
990 fields
991 .iter()
992 .filter_map(|f| {
993 let mut skip = false;
994 for attr in &f.attrs {
995 if attr_str(attr).as_deref() == Some("tags") {
996 skip |= attr.parse_args::<FieldTagArgs>().ok()?.skip;
997 }
998 }
999 let ty = &f.ty;
1000 (!skip).then_some(quote! { <#ty as ::object_rainbow::Tagged>::TAGS })
1001 })
1002 .collect()
1003}
1004
1005fn gen_tags(data: &Data, attrs: &[Attribute], errors: &mut Vec<Error>) -> proc_macro2::TokenStream {
1006 match data {
1007 Data::Struct(data) => {
1008 let mut tags = Vec::new();
1009 for attr in attrs {
1010 if attr_str(attr).as_deref() == Some("tags") {
1011 match attr.parse_args::<StructTagArgs>() {
1012 Ok(mut args) => tags.append(&mut args.tags),
1013 Err(e) => errors.push(e),
1014 }
1015 }
1016 }
1017 let nested = fields_tags(&data.fields);
1018 if nested.len() == 1 && tags.is_empty() {
1019 let nested = nested.into_iter().next().unwrap();
1020 quote! {
1021 #nested
1022 }
1023 } else {
1024 quote! {
1025 ::object_rainbow::Tags(&[#(#tags),*], &[#(&#nested),*])
1026 }
1027 }
1028 }
1029 Data::Enum(data) => {
1030 let mut tags = Vec::new();
1031 for attr in attrs {
1032 if attr_str(attr).as_deref() == Some("tags") {
1033 match attr.parse_args::<StructTagArgs>() {
1034 Ok(mut args) => tags.append(&mut args.tags),
1035 Err(e) => errors.push(e),
1036 }
1037 }
1038 }
1039 let mut nested: Vec<_> = data
1040 .variants
1041 .iter()
1042 .flat_map(|v| fields_tags(&v.fields))
1043 .collect();
1044 let kind_tags = quote! {
1045 <
1046 <
1047 <
1048 Self
1049 as
1050 ::object_rainbow::Enum
1051 >::Kind
1052 as
1053 ::object_rainbow::enumkind::EnumKind
1054 >::Tag
1055 as ::object_rainbow::Tagged
1056 >::TAGS
1057 };
1058 nested.insert(0, kind_tags);
1059 if nested.len() == 1 && tags.is_empty() {
1060 let nested = nested.into_iter().next().unwrap();
1061 quote! {
1062 #nested
1063 }
1064 } else {
1065 quote! {
1066 ::object_rainbow::Tags(&[#(#tags),*], &[#(&#nested),*])
1067 }
1068 }
1069 }
1070 Data::Union(data) => {
1071 Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1072 }
1073 }
1074}
1075
1076#[proc_macro_derive(Size)]
1098pub fn derive_size(input: TokenStream) -> TokenStream {
1099 let input = parse_macro_input!(input as DeriveInput);
1100 let name = input.ident;
1101 let size_arr = gen_size_arr(&input.data);
1102 let size = gen_size(&input.data);
1103 let (generics, is_enum) = match bounds_size(input.generics.clone(), &input.data, &size_arr) {
1104 Ok(g) => g,
1105 Err(e) => return e.into_compile_error().into(),
1106 };
1107 let (_, ty_generics, where_clause) = generics.split_for_impl();
1108 let mut generics = input.generics;
1109 if is_enum {
1110 generics.params.push(parse_quote!(
1111 __Output: ::object_rainbow::typenum::Unsigned
1112 ));
1113 }
1114 let (impl_generics, _, _) = generics.split_for_impl();
1115 let target = parse_for(&name, &input.attrs);
1116 let output = quote! {
1117 const _: () = {
1118 use ::object_rainbow::typenum::tarr;
1119
1120 #[automatically_derived]
1121 impl #impl_generics ::object_rainbow::Size for #target #ty_generics #where_clause {
1122 const SIZE: usize = #size;
1123
1124 type Size = <#size_arr as ::object_rainbow::typenum::FoldAdd>::Output;
1125 }
1126 };
1127 };
1128 TokenStream::from(output)
1129}
1130
1131fn bounds_size(
1132 mut generics: Generics,
1133 data: &Data,
1134 size_arr: &proc_macro2::TokenStream,
1135) -> syn::Result<(Generics, bool)> {
1136 let g = &bounds_g(&generics);
1137 let is_enum = match data {
1138 Data::Struct(data) => {
1139 for f in data.fields.iter() {
1140 let ty = &f.ty;
1141 if type_contains_generics(GContext { g, always: false }, ty) {
1142 generics.make_where_clause().predicates.push(
1143 parse_quote_spanned! { ty.span() =>
1144 #ty: ::object_rainbow::Size
1145 },
1146 );
1147 }
1148 }
1149 generics.make_where_clause().predicates.push(parse_quote!(
1150 #size_arr: ::object_rainbow::typenum::FoldAdd<
1151 Output: ::object_rainbow::typenum::Unsigned
1152 >
1153 ));
1154 false
1155 }
1156 Data::Enum(data) => {
1157 for v in data.variants.iter() {
1158 for f in v.fields.iter() {
1159 let ty = &f.ty;
1160 if type_contains_generics(GContext { g, always: false }, ty) {
1161 generics.make_where_clause().predicates.push(
1162 parse_quote_spanned! { ty.span() =>
1163 #ty: ::object_rainbow::Size
1164 },
1165 );
1166 }
1167 }
1168 }
1169 for v in data.variants.iter().skip(1) {
1170 let arr = fields_size_arr(&v.fields, true);
1171 generics.make_where_clause().predicates.push(parse_quote!(
1172 #arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
1173 ));
1174 }
1175 generics.make_where_clause().predicates.push(parse_quote!(
1176 #size_arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
1177 ));
1178 true
1179 }
1180 Data::Union(data) => {
1181 return Err(Error::new_spanned(
1182 data.union_token,
1183 "`union`s are not supported",
1184 ));
1185 }
1186 };
1187 Ok((generics, is_enum))
1188}
1189
1190fn fields_size_arr(fields: &syn::Fields, as_enum: bool) -> proc_macro2::TokenStream {
1191 let kind_size = quote! {
1192 <
1193 <
1194 <
1195 Self
1196 as
1197 ::object_rainbow::Enum
1198 >::Kind
1199 as
1200 ::object_rainbow::enumkind::EnumKind
1201 >::Tag
1202 as ::object_rainbow::Size
1203 >::Size
1204 };
1205 if fields.is_empty() {
1206 return if as_enum {
1207 quote! { tarr![#kind_size, ::object_rainbow::typenum::consts::U0] }
1208 } else {
1209 quote! { tarr![::object_rainbow::typenum::consts::U0] }
1210 };
1211 }
1212 let size_arr = fields.iter().map(|f| {
1213 let ty = &f.ty;
1214 quote! { <#ty as ::object_rainbow::Size>::Size }
1215 });
1216 if as_enum {
1217 quote! { tarr![#kind_size, ::object_rainbow::typenum::consts::U0, #(#size_arr),*] }
1218 } else {
1219 quote! { tarr![::object_rainbow::typenum::consts::U0, #(#size_arr),*] }
1220 }
1221}
1222
1223fn gen_size_arr(data: &Data) -> proc_macro2::TokenStream {
1224 match data {
1225 Data::Struct(data) => fields_size_arr(&data.fields, false),
1226 Data::Enum(data) => {
1227 if let Some(v) = data.variants.first() {
1228 fields_size_arr(&v.fields, true)
1229 } else {
1230 Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
1231 .into_compile_error()
1232 }
1233 }
1234 Data::Union(data) => {
1235 Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1236 }
1237 }
1238}
1239
1240fn fields_size(fields: &syn::Fields) -> proc_macro2::TokenStream {
1241 if fields.is_empty() {
1242 return quote! {0};
1243 }
1244 let size = fields.iter().map(|f| {
1245 let ty = &f.ty;
1246 quote! { <#ty as ::object_rainbow::Size>::SIZE }
1247 });
1248 quote! {
1249 #(#size)+*
1250 }
1251}
1252
1253fn gen_size(data: &Data) -> proc_macro2::TokenStream {
1254 match data {
1255 Data::Struct(data) => fields_size(&data.fields),
1256 Data::Enum(data) => {
1257 if let Some(v) = data.variants.first() {
1258 let size = fields_size(&v.fields);
1259 let kind_size = quote! {
1260 <
1261 <
1262 <
1263 Self
1264 as
1265 ::object_rainbow::Enum
1266 >::Kind
1267 as
1268 ::object_rainbow::enumkind::EnumKind
1269 >::Tag
1270 as ::object_rainbow::Size
1271 >::SIZE
1272 };
1273 quote! { #kind_size + #size }
1274 } else {
1275 Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
1276 .into_compile_error()
1277 }
1278 }
1279 Data::Union(data) => {
1280 Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1281 }
1282 }
1283}
1284
1285#[proc_macro_derive(Parse, attributes(parse))]
1306pub fn derive_parse(input: TokenStream) -> TokenStream {
1307 let input = parse_macro_input!(input as DeriveInput);
1308 let name = input.ident;
1309 let generics = input.generics.clone();
1310 let (_, ty_generics, _) = generics.split_for_impl();
1311 let mut defs = Vec::new();
1312 let generics = match bounds_parse(input.generics, &input.data, &input.attrs, &name, &mut defs) {
1313 Ok(g) => g,
1314 Err(e) => return e.into_compile_error().into(),
1315 };
1316 let (parse, enum_parse) = gen_parse(&input.data, &ty_generics);
1317 let (impl_generics, _, where_clause) = generics.split_for_impl();
1318 let target = parse_for(&name, &input.attrs);
1319 let enum_parse = enum_parse.map(|enum_parse| {
1320 quote! {
1321 #[automatically_derived]
1322 impl #impl_generics ::object_rainbow::enumkind::EnumParse<__I> for #target #ty_generics
1323 #where_clause
1324 {
1325 fn enum_parse(
1326 kind: <Self as ::object_rainbow::Enum>::Kind, mut input: __I,
1327 ) -> ::object_rainbow::Result<Self> {
1328 #enum_parse
1329 }
1330 }
1331 }
1332 });
1333 let output = quote! {
1334 const _: () = {
1335 #(#defs)*
1336
1337 #[automatically_derived]
1338 impl #impl_generics ::object_rainbow::Parse<__I> for #target #ty_generics
1339 #where_clause
1340 {
1341 fn parse(mut input: __I) -> ::object_rainbow::Result<Self> {
1342 #parse
1343 }
1344 }
1345
1346 #enum_parse
1347 };
1348 };
1349 TokenStream::from(output)
1350}
1351
1352#[derive(Debug, FromMeta)]
1353#[darling(derive_syn_parse)]
1354struct ParseArgs {
1355 bound: Option<Type>,
1356 #[darling(default)]
1357 unchecked: bool,
1358 with: Option<Expr>,
1359 #[darling(default, rename = "unstable_mutual")]
1360 mutual: bool,
1361}
1362
1363fn conditional_parse_name(f: &Field, inline: bool) -> Ident {
1364 let infix = if inline { "ParseInline" } else { "Parse" };
1365 let conditional = format!("__Conditional{infix}_{}", f.ident.as_ref().unwrap());
1366 Ident::new(&conditional, f.span())
1367}
1368
1369fn conditional_parse_input(inline: bool) -> proc_macro2::TokenStream {
1370 if inline {
1371 quote!(&mut impl ::object_rainbow::PointInput<Extra = Self::E>)
1372 } else {
1373 quote!(impl ::object_rainbow::PointInput<Extra = Self::E>)
1374 }
1375}
1376
1377fn conditional_parse_method(inline: bool) -> proc_macro2::TokenStream {
1378 if inline {
1379 quote!(parse_inline)
1380 } else {
1381 quote!(parse)
1382 }
1383}
1384
1385fn bounds_parse(
1386 mut generics: Generics,
1387 data: &Data,
1388 attrs: &[Attribute],
1389 name: &Ident,
1390 defs: &mut Vec<proc_macro2::TokenStream>,
1391) -> syn::Result<Generics> {
1392 let g_clone = generics.clone();
1393 let (impl_generics, ty_generics, where_clause) = g_clone.split_for_impl();
1394 let this = quote_spanned! { name.span() =>
1395 #name #ty_generics
1396 };
1397 let (recursive, _) = parse_recursive_inline(attrs)?;
1398 let tr = |last| match (last, recursive) {
1399 (true, true) => {
1400 quote!(::object_rainbow::Parse<__I> + ::object_rainbow::Object<__I::Extra>)
1401 }
1402 (true, false) => quote!(::object_rainbow::Parse<__I>),
1403 (false, true) => {
1404 quote!(::object_rainbow::ParseInline<__I> + ::object_rainbow::Inline<__I::Extra>)
1405 }
1406 (false, false) => quote!(::object_rainbow::ParseInline<__I>),
1407 };
1408 match data {
1409 Data::Struct(data) => {
1410 let last_at = data.fields.len().saturating_sub(1);
1411 'field: for (i, f) in data.fields.iter().enumerate() {
1412 let last = i == last_at;
1413 let ty = &f.ty;
1414 let mut b = None;
1415 for attr in &f.attrs {
1416 if attr_str(attr).as_deref() == Some("parse") {
1417 let ParseArgs {
1418 bound,
1419 unchecked,
1420 mutual,
1421 ..
1422 } = attr.parse_args::<ParseArgs>()?;
1423 if mutual {
1424 let conditional = conditional_parse_name(f, !last);
1425 let mut g_clone = g_clone.clone();
1426 g_clone.params.push(parse_quote!(
1427 __E: ::core::marker::Send + ::core::marker::Sync
1428 ));
1429 let (impl_generics_extra, _, _) = g_clone.split_for_impl();
1430 let input_type = conditional_parse_input(!last);
1431 let parse_method = conditional_parse_method(!last);
1432 defs.push(quote! {
1433 #[allow(non_camel_case_types)]
1434 trait #conditional #impl_generics: ::object_rainbow::BoundPair
1435 #where_clause
1436 {
1437 fn parse(
1438 input: #input_type,
1439 ) -> ::object_rainbow::Result<Self::T>
1440 where #this: ::object_rainbow::Object<Self::E>;
1441 }
1442
1443 impl #impl_generics_extra #conditional #ty_generics
1444 for (#ty, __E)
1445 #where_clause
1446 {
1447 fn parse(
1448 input: #input_type,
1449 ) -> ::object_rainbow::Result<Self::T>
1450 where #this: ::object_rainbow::Object<Self::E> {
1451 input.#parse_method::<Self::T>()
1452 }
1453 }
1454 });
1455 b = Some(parse_quote!(#conditional #ty_generics));
1456 }
1457 if unchecked {
1458 continue 'field;
1459 }
1460 if let Some(bound) = bound {
1461 b = Some(bound);
1462 }
1463 }
1464 }
1465 if let Some(bound) = b {
1466 generics.make_where_clause().predicates.push(
1467 parse_quote_spanned! { ty.span() =>
1468 (#ty, __I::Extra): ::object_rainbow::BoundPair<
1469 T = #ty, E = __I::Extra
1470 > + #bound
1471 },
1472 );
1473 } else {
1474 let tr = tr(last);
1475 generics.make_where_clause().predicates.push(
1476 parse_quote_spanned! { ty.span() =>
1477 #ty: #tr
1478 },
1479 );
1480 }
1481 }
1482 }
1483 Data::Enum(data) => {
1484 for v in data.variants.iter() {
1485 let last_at = v.fields.len().saturating_sub(1);
1486 'field: for (i, f) in v.fields.iter().enumerate() {
1487 let ty = &f.ty;
1488 let mut b = None;
1489 for attr in &f.attrs {
1490 if attr_str(attr).as_deref() == Some("parse") {
1491 let ParseArgs {
1492 bound, unchecked, ..
1493 } = attr.parse_args::<ParseArgs>()?;
1494 if unchecked {
1495 continue 'field;
1496 }
1497 if let Some(bound) = bound {
1498 b = Some(bound);
1499 }
1500 }
1501 }
1502 if let Some(bound) = b {
1503 generics.make_where_clause().predicates.push(
1504 parse_quote_spanned! { ty.span() =>
1505 (#ty, __I::Extra): ::object_rainbow::BoundPair<
1506 T = #ty, E = __I::Extra
1507 > + #bound
1508 },
1509 );
1510 } else {
1511 let last = i == last_at;
1512 let tr = tr(last);
1513 generics.make_where_clause().predicates.push(
1514 parse_quote_spanned! { ty.span() =>
1515 #ty: #tr
1516 },
1517 );
1518 }
1519 }
1520 }
1521 }
1522 Data::Union(data) => {
1523 return Err(Error::new_spanned(
1524 data.union_token,
1525 "`union`s are not supported",
1526 ));
1527 }
1528 }
1529 generics.params.push(if recursive {
1530 parse_quote!(__I: ::object_rainbow::PointInput<
1531 Extra: ::core::marker::Send + ::core::marker::Sync + ::core::clone::Clone
1532 >)
1533 } else {
1534 parse_quote!(__I: ::object_rainbow::ParseInput)
1535 });
1536 Ok(generics)
1537}
1538
1539fn gen_parse(
1540 data: &Data,
1541 ty_generics: &TypeGenerics<'_>,
1542) -> (proc_macro2::TokenStream, Option<proc_macro2::TokenStream>) {
1543 match data {
1544 Data::Struct(data) => {
1545 let arm = fields_parse(&data.fields, ty_generics);
1546 (quote! { Ok(Self #arm)}, None)
1547 }
1548 Data::Enum(data) => {
1549 let parse = data.variants.iter().map(|v| {
1550 let ident = &v.ident;
1551 let arm = fields_parse(&v.fields, ty_generics);
1552 quote! {
1553 <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
1554 }
1555 });
1556 (
1557 quote! {
1558 ::object_rainbow::enumkind::EnumParse::parse_as_enum(input)
1559 },
1560 Some(quote! {
1561 Ok(match kind {
1562 #(#parse)*
1563 })
1564 }),
1565 )
1566 }
1567 Data::Union(data) => (
1568 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error(),
1569 None,
1570 ),
1571 }
1572}
1573
1574fn fields_parse(fields: &syn::Fields, ty_generics: &TypeGenerics<'_>) -> proc_macro2::TokenStream {
1575 let last_at = fields.len().saturating_sub(1);
1576 match fields {
1577 syn::Fields::Named(fields) => {
1578 let parse = fields.named.iter().enumerate().map(|(i, f)| {
1579 let last = i == last_at;
1580 let ty = &f.ty;
1581 let mut w = None;
1582 let mut b = None;
1583 for attr in &f.attrs {
1584 if attr_str(attr).as_deref() == Some("parse") {
1585 let ParseArgs {
1586 with,
1587 bound,
1588 mutual,
1589 ..
1590 } = match attr.parse_args::<ParseArgs>() {
1591 Ok(args) => args,
1592 Err(e) => return e.into_compile_error(),
1593 };
1594 if mutual {
1595 let conditional = format!(
1596 "__Conditional{}_{}",
1597 if last { "Parse" } else { "ParseInline" },
1598 f.ident.as_ref().unwrap(),
1599 );
1600 let conditional = Ident::new(&conditional, f.span());
1601 w = Some(parse_quote!(parse));
1602 b = Some(parse_quote!(#conditional #ty_generics));
1603 }
1604 if let Some(with) = with {
1605 w = Some(with);
1606 }
1607 if let Some(bound) = bound {
1608 b = Some(bound);
1609 }
1610 }
1611 }
1612 let i = f.ident.as_ref().unwrap();
1613 if let Some(with) = w {
1614 let arg = if last {
1615 quote!(input)
1616 } else {
1617 quote!(&mut input)
1618 };
1619 if let Some(bound) = b {
1620 quote_spanned! { f.ty.span() =>
1621 #i: <(#ty, __I::Extra) as #bound>::#with(#arg)?
1622 }
1623 } else {
1624 quote_spanned! { f.ty.span() =>
1625 #i: #with(#arg)?
1626 }
1627 }
1628 } else {
1629 let method = if last {
1630 quote!(parse)
1631 } else {
1632 quote!(parse_inline)
1633 };
1634 quote_spanned! { f.ty.span() =>
1635 #i: input.#method()?
1636 }
1637 }
1638 });
1639 quote! { { #(#parse),* } }
1640 }
1641 syn::Fields::Unnamed(fields) => {
1642 let parse = fields.unnamed.iter().enumerate().map(|(i, f)| {
1643 let ty = &f.ty;
1644 let mut w = None;
1645 let mut b = None;
1646 for attr in &f.attrs {
1647 if attr_str(attr).as_deref() == Some("parse") {
1648 let ParseArgs { with, bound, .. } = match attr.parse_args::<ParseArgs>() {
1649 Ok(args) => args,
1650 Err(e) => return e.into_compile_error(),
1651 };
1652 if let Some(with) = with {
1653 w = Some(with);
1654 }
1655 if let Some(bound) = bound {
1656 b = Some(bound);
1657 }
1658 }
1659 }
1660 let last = i == last_at;
1661 if let Some(with) = w {
1662 let arg = if last {
1663 quote!(input)
1664 } else {
1665 quote!(&mut input)
1666 };
1667 if let Some(bound) = b {
1668 quote_spanned! { f.ty.span() =>
1669 <(#ty, __I::Extra) as #bound>::#with(#arg)?
1670 }
1671 } else {
1672 quote_spanned! { f.ty.span() =>
1673 #with(#arg)?
1674 }
1675 }
1676 } else {
1677 let method = if last {
1678 quote!(parse)
1679 } else {
1680 quote!(parse_inline)
1681 };
1682 quote_spanned! { f.ty.span() =>
1683 input.#method()?
1684 }
1685 }
1686 });
1687 quote! { (#(#parse),*) }
1688 }
1689 syn::Fields::Unit => quote! {},
1690 }
1691}
1692
1693#[proc_macro_derive(ParseInline, attributes(parse))]
1714pub fn derive_parse_inline(input: TokenStream) -> TokenStream {
1715 let input = parse_macro_input!(input as DeriveInput);
1716 let name = input.ident;
1717 let generics = input.generics.clone();
1718 let (_, ty_generics, _) = generics.split_for_impl();
1719 let generics = match bounds_parse_inline(input.generics, &input.data, &input.attrs) {
1720 Ok(g) => g,
1721 Err(e) => return e.into_compile_error().into(),
1722 };
1723 let (parse_inline, enum_parse_inline) = gen_parse_inline(&input.data);
1724 let (impl_generics, _, where_clause) = generics.split_for_impl();
1725 let target = parse_for(&name, &input.attrs);
1726 let enum_parse_inline = enum_parse_inline.map(|enum_parse_inline| {
1727 quote! {
1728 #[automatically_derived]
1729 impl #impl_generics ::object_rainbow::enumkind::EnumParseInline<__I>
1730 for #target #ty_generics #where_clause {
1731 fn enum_parse_inline(
1732 kind: <Self as ::object_rainbow::Enum>::Kind, input: &mut __I,
1733 ) -> ::object_rainbow::Result<Self> {
1734 #enum_parse_inline
1735 }
1736 }
1737 }
1738 });
1739 let output = quote! {
1740 #[automatically_derived]
1741 impl #impl_generics ::object_rainbow::ParseInline<__I>
1742 for #target #ty_generics #where_clause {
1743 fn parse_inline(input: &mut __I) -> ::object_rainbow::Result<Self> {
1744 #parse_inline
1745 }
1746 }
1747
1748 #enum_parse_inline
1749 };
1750 TokenStream::from(output)
1751}
1752
1753fn bounds_parse_inline(
1754 mut generics: Generics,
1755 data: &Data,
1756 attrs: &[Attribute],
1757) -> syn::Result<Generics> {
1758 let (recursive, _) = parse_recursive_inline(attrs)?;
1759 let tr = if recursive {
1760 quote!(::object_rainbow::ParseInline<__I> + ::object_rainbow::Inline<__I::Extra>)
1761 } else {
1762 quote!(::object_rainbow::ParseInline<__I>)
1763 };
1764 match data {
1765 Data::Struct(data) => {
1766 'field: for f in data.fields.iter() {
1767 let ty = &f.ty;
1768 let mut b = None;
1769 for attr in &f.attrs {
1770 if attr_str(attr).as_deref() == Some("parse") {
1771 let ParseArgs {
1772 bound, unchecked, ..
1773 } = attr.parse_args::<ParseArgs>()?;
1774 if unchecked {
1775 continue 'field;
1776 }
1777 if let Some(bound) = bound {
1778 b = Some(bound);
1779 }
1780 }
1781 }
1782 if let Some(bound) = b {
1783 generics.make_where_clause().predicates.push(
1784 parse_quote_spanned! { ty.span() =>
1785 (#ty, __I::Extra): #bound
1786 },
1787 );
1788 } else {
1789 generics.make_where_clause().predicates.push(
1790 parse_quote_spanned! { ty.span() =>
1791 #ty: #tr
1792 },
1793 );
1794 }
1795 }
1796 }
1797 Data::Enum(data) => {
1798 for v in data.variants.iter() {
1799 'field: for f in v.fields.iter() {
1800 let ty = &f.ty;
1801 let mut b = None;
1802 for attr in &f.attrs {
1803 if attr_str(attr).as_deref() == Some("parse") {
1804 let ParseArgs {
1805 bound, unchecked, ..
1806 } = attr.parse_args::<ParseArgs>()?;
1807 if unchecked {
1808 continue 'field;
1809 }
1810 if let Some(bound) = bound {
1811 b = Some(bound);
1812 }
1813 }
1814 }
1815 if let Some(bound) = b {
1816 generics.make_where_clause().predicates.push(
1817 parse_quote_spanned! { ty.span() =>
1818 (#ty, __I::Extra): #bound
1819 },
1820 );
1821 } else {
1822 generics.make_where_clause().predicates.push(
1823 parse_quote_spanned! { ty.span() =>
1824 #ty: #tr
1825 },
1826 );
1827 }
1828 }
1829 }
1830 }
1831 Data::Union(data) => {
1832 return Err(Error::new_spanned(
1833 data.union_token,
1834 "`union`s are not supported",
1835 ));
1836 }
1837 }
1838 generics.params.push(if recursive {
1839 parse_quote!(__I: ::object_rainbow::PointInput<
1840 Extra: ::core::marker::Send + ::core::marker::Sync
1841 >)
1842 } else {
1843 parse_quote!(__I: ::object_rainbow::ParseInput)
1844 });
1845 Ok(generics)
1846}
1847
1848fn fields_parse_inline(fields: &syn::Fields) -> proc_macro2::TokenStream {
1849 match fields {
1850 syn::Fields::Named(fields) => {
1851 let parse = fields.named.iter().map(|f| {
1852 let i = f.ident.as_ref().unwrap();
1853 quote_spanned! { f.ty.span() =>
1854 #i: input.parse_inline()?
1855 }
1856 });
1857 quote! { { #(#parse),* } }
1858 }
1859 syn::Fields::Unnamed(fields) => {
1860 let parse = fields.unnamed.iter().map(|f| {
1861 quote_spanned! { f.ty.span() =>
1862 input.parse_inline()?
1863 }
1864 });
1865 quote! { (#(#parse),*) }
1866 }
1867 syn::Fields::Unit => quote! {},
1868 }
1869}
1870
1871fn gen_parse_inline(data: &Data) -> (proc_macro2::TokenStream, Option<proc_macro2::TokenStream>) {
1872 match data {
1873 Data::Struct(data) => {
1874 let arm = fields_parse_inline(&data.fields);
1875 (quote! { Ok(Self #arm) }, None)
1876 }
1877 Data::Enum(data) => {
1878 let parse_inline = data.variants.iter().map(|v| {
1879 let ident = &v.ident;
1880 let arm = fields_parse_inline(&v.fields);
1881 quote! {
1882 <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
1883 }
1884 });
1885 (
1886 quote! {
1887 ::object_rainbow::enumkind::EnumParseInline::parse_as_inline_enum(input)
1888 },
1889 Some(quote! {
1890 Ok(match kind {
1891 #(#parse_inline)*
1892 })
1893 }),
1894 )
1895 }
1896 Data::Union(data) => (
1897 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error(),
1898 None,
1899 ),
1900 }
1901}
1902
1903#[proc_macro_derive(ParseAsInline)]
1920pub fn derive_parse_as_inline(input: TokenStream) -> TokenStream {
1921 let input = parse_macro_input!(input as DeriveInput);
1922 let name = input.ident;
1923 let generics = input.generics.clone();
1924 let (_, ty_generics, _) = generics.split_for_impl();
1925 let generics = match bounds_parse_as_inline(input.generics, &name) {
1926 Ok(g) => g,
1927 Err(e) => return e.into_compile_error().into(),
1928 };
1929 let (impl_generics, _, where_clause) = generics.split_for_impl();
1930 let target = parse_for(&name, &input.attrs);
1931 let output = quote! {
1932 #[automatically_derived]
1933 impl #impl_generics ::object_rainbow::Parse<__I> for #target #ty_generics #where_clause {
1934 fn parse(input: __I) -> ::object_rainbow::Result<Self> {
1935 ::object_rainbow::ParseInline::<__I>::parse_as_inline(input)
1936 }
1937 }
1938 };
1939 TokenStream::from(output)
1940}
1941
1942fn bounds_parse_as_inline(mut generics: Generics, name: &Ident) -> syn::Result<Generics> {
1943 generics
1944 .make_where_clause()
1945 .predicates
1946 .push(parse_quote_spanned! { name.span() =>
1947 Self: ::object_rainbow::ParseInline::<__I>
1948 });
1949 generics
1950 .params
1951 .push(parse_quote!(__I: ::object_rainbow::ParseInput));
1952 Ok(generics)
1953}
1954
1955fn parse_path(attr: &Attribute) -> syn::Result<Type> {
1956 attr.parse_args::<LitStr>()?.parse()
1957}
1958
1959fn attr_str(attr: &Attribute) -> Option<String> {
1960 Some(attr.path().get_ident()?.to_string())
1961}
1962
1963#[proc_macro_derive(Enum, attributes(enumtag))]
2023pub fn derive_enum(input: TokenStream) -> TokenStream {
2024 let input = parse_macro_input!(input as DeriveInput);
2025 let name = input.ident;
2026 let generics = input.generics.clone();
2027 let (_, ty_generics, _) = generics.split_for_impl();
2028 let generics = input.generics;
2029 let length = gen_length(&input.data);
2030 let variants = gen_variants(&input.data);
2031 let variant_count = gen_variant_count(&input.data);
2032 let to_tag = gen_to_tag(&input.data);
2033 let from_tag = gen_from_tag(&input.data);
2034 let kind = gen_kind(&input.data);
2035 let (impl_generics, _, where_clause) = generics.split_for_impl();
2036 let mut errors = Vec::new();
2037 let mut enumtag = None;
2038 for attr in &input.attrs {
2039 if attr_str(attr).as_deref() == Some("enumtag") {
2040 match parse_path(attr) {
2041 Ok(path) => {
2042 if enumtag.is_some() {
2043 errors.push(Error::new_spanned(path, "duplicate tag"));
2044 } else {
2045 enumtag = Some(path);
2046 }
2047 }
2048 Err(e) => errors.push(e),
2049 }
2050 }
2051 }
2052 let enumtag = enumtag.unwrap_or_else(|| {
2053 parse_quote!(
2054 ::object_rainbow::partial_byte_tag::PartialByteTag<#length>
2055 )
2056 });
2057 let errors = errors.into_iter().map(|e| e.into_compile_error());
2058 let target = parse_for(&name, &input.attrs);
2059 let output = quote! {
2060 const _: () = {
2061 #(#errors)*
2062
2063 use ::object_rainbow::enumkind::EnumKind;
2064
2065 #[derive(Clone, Copy, ::object_rainbow::ParseAsInline)]
2066 pub enum __Kind {
2067 #variants
2068 }
2069
2070 #[automatically_derived]
2071 impl ::object_rainbow::enumkind::EnumKind for __Kind {
2072 type Tag = ::object_rainbow::enumkind::EnumTag<
2073 #enumtag,
2074 #variant_count,
2075 >;
2076
2077 fn to_tag(self) -> Self::Tag {
2078 #to_tag
2079 }
2080
2081 fn from_tag(tag: Self::Tag) -> Self {
2082 #from_tag
2083 }
2084 }
2085
2086 impl<I: ::object_rainbow::ParseInput> ::object_rainbow::ParseInline<I> for __Kind {
2087 fn parse_inline(input: &mut I) -> ::object_rainbow::Result<Self> {
2088 Ok(::object_rainbow::enumkind::EnumKind::from_tag(input.parse_inline()?))
2089 }
2090 }
2091
2092 #[automatically_derived]
2093 impl #impl_generics ::object_rainbow::Enum for #target #ty_generics #where_clause {
2094 type Kind = __Kind;
2095
2096 fn kind(&self) -> Self::Kind {
2097 #kind
2098 }
2099 }
2100 };
2101 };
2102 TokenStream::from(output)
2103}
2104
2105fn gen_length(data: &Data) -> proc_macro2::TokenStream {
2106 match data {
2107 Data::Struct(data) => {
2108 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2109 }
2110 Data::Enum(data) => {
2111 let name = format!("U{}", data.variants.len());
2112 let ident = Ident::new(&name, data.variants.span());
2113 quote! { ::object_rainbow::typenum::#ident }
2114 }
2115 Data::Union(data) => {
2116 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2117 }
2118 }
2119}
2120
2121fn gen_variants(data: &Data) -> proc_macro2::TokenStream {
2122 match data {
2123 Data::Struct(data) => {
2124 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2125 }
2126 Data::Enum(data) => {
2127 let variants = data.variants.iter().map(|v| &v.ident);
2128 quote! { #(#variants),* }
2129 }
2130 Data::Union(data) => {
2131 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2132 }
2133 }
2134}
2135
2136fn gen_variant_count(data: &Data) -> proc_macro2::TokenStream {
2137 match data {
2138 Data::Struct(data) => {
2139 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2140 }
2141 Data::Enum(data) => {
2142 let variant_count = data.variants.len();
2143 quote! { #variant_count }
2144 }
2145 Data::Union(data) => {
2146 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2147 }
2148 }
2149}
2150
2151fn gen_to_tag(data: &Data) -> proc_macro2::TokenStream {
2152 match data {
2153 Data::Struct(data) => {
2154 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2155 }
2156 Data::Enum(data) => {
2157 let to_tag = data.variants.iter().enumerate().map(|(i, v)| {
2158 let ident = &v.ident;
2159 quote_spanned! { ident.span() =>
2160 Self::#ident => ::object_rainbow::enumkind::EnumTag::from_const::<#i>(),
2161 }
2162 });
2163 quote! {
2164 match self {
2165 #(#to_tag)*
2166 }
2167 }
2168 }
2169 Data::Union(data) => {
2170 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2171 }
2172 }
2173}
2174
2175fn gen_from_tag(data: &Data) -> proc_macro2::TokenStream {
2176 match data {
2177 Data::Struct(data) => {
2178 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2179 }
2180 Data::Enum(data) => {
2181 let from_tag = data.variants.iter().enumerate().map(|(i, v)| {
2182 let ident = &v.ident;
2183 quote_spanned! { ident.span() =>
2184 #i => Self::#ident,
2185 }
2186 });
2187 quote! {
2188 match tag.to_usize() {
2189 #(#from_tag)*
2190 _ => unreachable!(),
2191 }
2192 }
2193 }
2194 Data::Union(data) => {
2195 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2196 }
2197 }
2198}
2199
2200fn gen_kind(data: &Data) -> proc_macro2::TokenStream {
2201 match data {
2202 Data::Struct(data) => {
2203 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2204 }
2205 Data::Enum(data) => {
2206 let variants = data.variants.iter().map(|v| {
2207 let ident = &v.ident;
2208 quote_spanned! { ident.span() =>
2209 Self::#ident {..} => __Kind::#ident,
2210 }
2211 });
2212 quote! {
2213 match self {
2214 #(#variants)*
2215 }
2216 }
2217 }
2218 Data::Union(data) => {
2219 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2220 }
2221 }
2222}
2223
2224#[proc_macro_derive(MaybeHasNiche)]
2237pub fn derive_maybe_has_niche(input: TokenStream) -> TokenStream {
2238 let input = parse_macro_input!(input as DeriveInput);
2239 let name = input.ident;
2240 let mn_array = gen_mn_array(&input.data);
2241 let (_, ty_generics, _) = input.generics.split_for_impl();
2242 let generics = match bounds_maybe_has_niche(input.generics.clone(), &input.data) {
2243 Ok(g) => g,
2244 Err(e) => return e.into_compile_error().into(),
2245 };
2246 let (impl_generics, _, where_clause) = generics.split_for_impl();
2247 let target = parse_for(&name, &input.attrs);
2248 let output = quote! {
2249 const _: () = {
2250 use ::object_rainbow::typenum::tarr;
2251
2252 #[automatically_derived]
2253 impl #impl_generics ::object_rainbow::MaybeHasNiche
2254 for #target #ty_generics #where_clause {
2255 type MnArray = #mn_array;
2256 }
2257 };
2258 };
2259 TokenStream::from(output)
2260}
2261
2262fn bounds_maybe_has_niche(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
2263 match data {
2264 Data::Struct(data) => {
2265 for f in data.fields.iter() {
2266 let ty = &f.ty;
2267 generics
2268 .make_where_clause()
2269 .predicates
2270 .push(parse_quote_spanned! { ty.span() =>
2271 #ty: ::object_rainbow::MaybeHasNiche<
2272 MnArray: ::object_rainbow::MnArray<
2273 MaybeNiche: ::object_rainbow::MaybeNiche
2274 >
2275 >
2276 });
2277 }
2278 }
2279 Data::Enum(data) => {
2280 generics.params.push(parse_quote!(
2281 __N: ::object_rainbow::typenum::Unsigned
2282 ));
2283 for (i, v) in data.variants.iter().enumerate() {
2284 let mn_array = fields_mn_array(&v.fields, Some(i));
2285 generics
2286 .make_where_clause()
2287 .predicates
2288 .push(parse_quote_spanned! { v.span() =>
2289 #mn_array: ::object_rainbow::MnArray<
2290 MaybeNiche: ::object_rainbow::NicheOr<N = __N>
2291 >
2292 });
2293 for f in v.fields.iter() {
2294 let ty = &f.ty;
2295 generics.make_where_clause().predicates.push(
2296 parse_quote_spanned! { ty.span() =>
2297 #ty: ::object_rainbow::MaybeHasNiche<
2298 MnArray: ::object_rainbow::MnArray<
2299 MaybeNiche: ::object_rainbow::MaybeNiche
2300 >
2301 >
2302 },
2303 );
2304 }
2305 }
2306 }
2307 Data::Union(data) => {
2308 return Err(Error::new_spanned(
2309 data.union_token,
2310 "`union`s are not supported",
2311 ));
2312 }
2313 }
2314 Ok(generics)
2315}
2316
2317fn fields_mn_array(fields: &syn::Fields, variant: Option<usize>) -> proc_macro2::TokenStream {
2318 let mn_array = fields.iter().map(|f| {
2319 let ty = &f.ty;
2320 quote! {
2321 <
2322 <
2323 #ty
2324 as
2325 ::object_rainbow::MaybeHasNiche
2326 >::MnArray
2327 as
2328 ::object_rainbow::MnArray
2329 >::MaybeNiche
2330 }
2331 });
2332 if let Some(variant) = variant {
2333 let kind_niche = quote! {
2334 ::object_rainbow::AutoEnumNiche<Self, #variant>
2335 };
2336 quote! {
2337 tarr![
2338 #kind_niche,
2339 ::object_rainbow::NoNiche<::object_rainbow::HackNiche<#variant>>, #(#mn_array),*
2340 ]
2341 }
2342 } else {
2343 quote! { tarr![#(#mn_array),*] }
2344 }
2345}
2346
2347fn gen_mn_array(data: &Data) -> proc_macro2::TokenStream {
2348 match data {
2349 Data::Struct(data) => fields_mn_array(&data.fields, None),
2350 Data::Enum(data) => {
2351 let mn_array = data.variants.iter().enumerate().map(|(i, v)| {
2352 let mn_array = fields_mn_array(&v.fields, Some(i));
2353 quote! { <#mn_array as ::object_rainbow::MnArray>::MaybeNiche }
2354 });
2355 quote! {
2356 ::object_rainbow::NicheFoldOrArray<tarr![#(#mn_array),*]>
2357 }
2358 }
2359 Data::Union(data) => {
2360 Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
2361 }
2362 }
2363}
2364
2365#[proc_macro_attribute]
2366pub fn derive_for_wrapped(args: TokenStream, input: TokenStream) -> TokenStream {
2367 let input = parse_macro_input!(input as ItemTrait);
2368 let sup = if args.is_empty() {
2369 let sup = input.supertraits.clone();
2370 quote!(#sup)
2371 } else {
2372 args.into()
2373 };
2374 let name = input.ident.clone();
2375 let generics = input.generics.clone();
2376 let (_, ty_generics, _) = generics.split_for_impl();
2377 let mut derived = Vec::new();
2378 for (path, extra) in [
2379 (
2380 quote!(map_extra::MappedExtra),
2381 vec![(quote!(__M), quote!(#sup))],
2382 ),
2383 (quote!(length_prefixed::Lp), vec![]),
2384 ] {
2385 let mut generics = input.generics.clone();
2386 generics.params.push(parse_quote! {
2387 __T: #name #ty_generics
2388 });
2389 for (i, ty) in &extra {
2390 generics.params.push(parse_quote! {
2391 #i: #ty
2392 });
2393 }
2394 let (impl_generics, _, where_clause) = generics.split_for_impl();
2395 let i = input
2396 .items
2397 .clone()
2398 .into_iter()
2399 .map(|i| match i {
2400 TraitItem::Const(i) => ImplItem::Const({
2401 let const_token = i.const_token;
2402 let ident = i.ident;
2403 let colon_token = i.colon_token;
2404 let ty = i.ty;
2405 let semi_token = i.semi_token;
2406 parse_quote! {
2407 #const_token
2408 #ident
2409 #colon_token
2410 #ty
2411 =
2412 <__T as #name #ty_generics>::#ident
2413 #semi_token
2414 }
2415 }),
2416 TraitItem::Fn(i) => ImplItem::Fn({
2417 let mut sig = i.sig;
2418 let ident = sig.ident.clone();
2419 let args = sig
2420 .inputs
2421 .iter_mut()
2422 .enumerate()
2423 .map(|(n, i)| match i {
2424 FnArg::Receiver(receiver) => {
2425 let reference = receiver.reference.as_ref().map(|(and, _)| and);
2426 let mutability = receiver.mutability.as_ref();
2427 let ident = &receiver.self_token;
2428 quote!(#reference #mutability *#ident)
2429 }
2430 FnArg::Typed(pat_type) => {
2431 let ident = Ident::new(&format!("arg{n}"), pat_type.span());
2432 *pat_type.pat = parse_quote!(#ident);
2433 quote!(#ident)
2434 }
2435 })
2436 .collect::<Vec<_>>();
2437 parse_quote! {
2438 #sig
2439 {
2440 <__T as #name #ty_generics>::#ident(
2441 #(#args),*
2442 )
2443 }
2444 }
2445 }),
2446 TraitItem::Type(i) => ImplItem::Type({
2447 let type_token = i.type_token;
2448 let ident = i.ident;
2449 let semi_token = i.semi_token;
2450 parse_quote! {
2451 #type_token
2452 #ident
2453 =
2454 <__T as #name #ty_generics>::#ident
2455 #semi_token
2456 }
2457 }),
2458 _ => unimplemented!("unknown/unsupported item"),
2459 })
2460 .collect::<Vec<_>>();
2461 let extra = extra.into_iter().map(|(k, _)| k);
2462 derived.push(quote! {
2463 impl #impl_generics #name #ty_generics for ::object_rainbow::#path<
2464 __T,
2465 #(#extra),*
2466 >
2467 #where_clause
2468 {
2469 #(#i)*
2470 }
2471 });
2472 }
2473 let output = quote! {
2474 #input
2475
2476 #(#derived)*
2477 };
2478 output.into()
2479}