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, FnArg, GenericParam, Generics, Ident, ImplItem,
10 ItemTrait, LitStr, Path, TraitItem, Type, WherePredicate, parse::Parse, parse_macro_input,
11 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 impl ::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 generics = match bounds_topological(input.generics, &input.data, &input.attrs, &name) {
465 Ok(g) => g,
466 Err(e) => return e.into_compile_error().into(),
467 };
468 let traverse = gen_traverse(&input.data);
469 let (impl_generics, _, where_clause) = generics.split_for_impl();
470 let target = parse_for(&name, &input.attrs);
471 let output = quote! {
472 const _: () = {
473 #[automatically_derived]
474 impl #impl_generics ::object_rainbow::Topological for #target #ty_generics
475 #where_clause
476 {
477 fn traverse(&self, visitor: &mut impl ::object_rainbow::PointVisitor) {
478 #traverse
479 }
480 }
481 };
482 };
483 TokenStream::from(output)
484}
485
486#[derive(Debug, FromMeta)]
487#[darling(derive_syn_parse)]
488struct ContainerTopologyArgs {
489 #[darling(default)]
490 recursive: bool,
491 #[darling(default)]
492 inline: bool,
493 #[darling(default)]
494 unchecked: bool,
495 #[darling(default)]
496 bound: Option<LitStr>,
497}
498
499fn parse_recursive_inline(
500 attrs: &[Attribute],
501) -> syn::Result<(bool, bool, bool, Vec<WherePredicate>)> {
502 let mut r = false;
503 let mut i = false;
504 let mut u = false;
505 let mut wheres = Vec::new();
506 for attr in attrs {
507 if attr_str(attr).as_deref() == Some("topology") {
508 let ContainerTopologyArgs {
509 recursive,
510 inline,
511 unchecked,
512 bound,
513 } = attr.parse_args()?;
514 if recursive {
515 r = true;
516 }
517 if inline {
518 i = true;
519 }
520 if unchecked {
521 u = true;
522 }
523 if let Some(bound) = bound {
524 wheres.push(bound.parse()?);
525 }
526 }
527 }
528 Ok((r, i, u, wheres))
529}
530
531#[derive(Debug, FromMeta)]
532#[darling(derive_syn_parse)]
533struct FieldTopologyArgs {
534 bound: Option<Path>,
535 #[darling(default)]
536 unchecked: bool,
537 with: Option<Expr>,
538}
539
540fn bounds_topological(
541 mut generics: Generics,
542 data: &Data,
543 attrs: &[Attribute],
544 name: &Ident,
545) -> syn::Result<Generics> {
546 let (recursive, inline, u, wheres) = parse_recursive_inline(attrs)?;
547 let g = &bounds_g(&generics);
548 let bound = if recursive {
549 quote! { ::object_rainbow::Traversible }
550 } else {
551 quote! { ::object_rainbow::Topological }
552 };
553 match data {
554 Data::Struct(data) => {
555 'field: for f in data.fields.iter() {
556 let ty = &f.ty;
557 let mut b = None;
558 for attr in &f.attrs {
559 if attr_str(attr).as_deref() == Some("topology") {
560 let FieldTopologyArgs {
561 bound, unchecked, ..
562 } = attr.parse_args()?;
563 if unchecked {
564 continue 'field;
565 }
566 if let Some(bound) = bound {
567 b = Some(bound);
568 }
569 }
570 }
571 let bound = if let Some(bound) = b {
572 quote! { #bound }
573 } else {
574 if u {
575 continue 'field;
576 }
577 bound.clone()
578 };
579 if type_contains_generics(GContext { g, always: false }, ty) {
580 generics.make_where_clause().predicates.push(
581 parse_quote_spanned! { ty.span() =>
582 #ty: #bound
583 },
584 );
585 }
586 }
587 }
588 Data::Enum(data) => {
589 for v in data.variants.iter() {
590 'field: for f in v.fields.iter() {
591 let ty = &f.ty;
592 let mut b = None;
593 for attr in &f.attrs {
594 if attr_str(attr).as_deref() == Some("topology") {
595 let FieldTopologyArgs {
596 bound, unchecked, ..
597 } = attr.parse_args()?;
598 if unchecked {
599 continue 'field;
600 }
601 if let Some(bound) = bound {
602 b = Some(bound);
603 }
604 }
605 }
606 let bound = if let Some(bound) = b {
607 quote! { #bound }
608 } else {
609 if u {
610 continue 'field;
611 }
612 bound.clone()
613 };
614 if type_contains_generics(GContext { g, always: false }, ty) {
615 generics.make_where_clause().predicates.push(
616 parse_quote_spanned! { ty.span() =>
617 #ty: #bound
618 },
619 );
620 }
621 }
622 }
623 }
624 Data::Union(data) => {
625 return Err(Error::new_spanned(
626 data.union_token,
627 "`union`s are not supported",
628 ));
629 }
630 }
631 let output_bound = if inline {
632 quote! {
633 ::object_rainbow::InlineOutput
634 }
635 } else {
636 quote! {
637 ::object_rainbow::ToOutput
638 }
639 };
640 if recursive {
641 generics
642 .make_where_clause()
643 .predicates
644 .push(parse_quote_spanned! { name.span() =>
645 Self: #output_bound + ::object_rainbow::Tagged
646 });
647 }
648 for bound in wheres {
649 generics.make_where_clause().predicates.push(bound);
650 }
651 Ok(generics)
652}
653
654fn fields_traverse(fields: &syn::Fields) -> proc_macro2::TokenStream {
655 match fields {
656 syn::Fields::Named(fields) => {
657 let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
658 let traverse = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
659 let ty = &f.ty;
660 let mut w = None;
661 let mut b = None;
662 for attr in &f.attrs {
663 if attr_str(attr).as_deref() == Some("topology") {
664 let FieldTopologyArgs { with, bound, .. } = match attr.parse_args() {
665 Ok(args) => args,
666 Err(e) => return e.into_compile_error(),
667 };
668 if let Some(with) = with {
669 w = Some(with);
670 }
671 if let Some(bound) = bound {
672 b = Some(bound);
673 }
674 }
675 }
676 if let Some(with) = w {
677 if let Some(bound) = b {
678 quote_spanned! { f.ty.span() =>
679 <#ty as #bound>::#with(#i, visitor)
680 }
681 } else {
682 quote_spanned! { f.ty.span() =>
683 #with(#i, visitor)
684 }
685 }
686 } else {
687 quote_spanned! { f.ty.span() =>
688 #i.traverse(visitor)
689 }
690 }
691 });
692 quote! {
693 { #(#let_self),* } => {
694 #(#traverse);*
695 }
696 }
697 }
698 syn::Fields::Unnamed(fields) => {
699 let let_self = fields
700 .unnamed
701 .iter()
702 .enumerate()
703 .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
704 let traverse = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
705 let ty = &f.ty;
706 let mut w = None;
707 let mut b = None;
708 for attr in &f.attrs {
709 if attr_str(attr).as_deref() == Some("topology") {
710 let FieldTopologyArgs { with, bound, .. } = match attr.parse_args() {
711 Ok(args) => args,
712 Err(e) => return e.into_compile_error(),
713 };
714 if let Some(with) = with {
715 w = Some(with);
716 }
717 if let Some(bound) = bound {
718 b = Some(bound);
719 }
720 }
721 }
722 if let Some(with) = w {
723 if let Some(bound) = b {
724 quote_spanned! { f.ty.span() =>
725 <#ty as #bound>::#with(#i, visitor)
726 }
727 } else {
728 quote_spanned! { f.ty.span() =>
729 #with(#i, visitor)
730 }
731 }
732 } else {
733 quote_spanned! { f.ty.span() =>
734 #i.traverse(visitor)
735 }
736 }
737 });
738 quote! {
739 (#(#let_self),*) => {
740 #(#traverse);*
741 }
742 }
743 }
744 syn::Fields::Unit => quote! {
745 => {}
746 },
747 }
748}
749
750fn gen_traverse(data: &Data) -> proc_macro2::TokenStream {
751 match data {
752 Data::Struct(data) => {
753 let arm = fields_traverse(&data.fields);
754 quote! {
755 match self {
756 Self #arm
757 }
758 }
759 }
760 Data::Enum(data) => {
761 let to_output = data.variants.iter().map(|v| {
762 let ident = &v.ident;
763 let arm = fields_traverse(&v.fields);
764 quote! { Self::#ident #arm }
765 });
766 quote! {
767 let kind = ::object_rainbow::Enum::kind(self);
768 let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
769 tag.traverse(visitor);
770 match self {
771 #(#to_output)*
772 }
773 }
774 }
775 Data::Union(data) => {
776 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
777 }
778 }
779}
780
781#[proc_macro_derive(Tagged, attributes(tags))]
801pub fn derive_tagged(input: TokenStream) -> TokenStream {
802 let input = parse_macro_input!(input as DeriveInput);
803 let name = input.ident;
804 let mut errors = Vec::new();
805 let generics = match bounds_tagged(input.generics, &input.data, &mut errors) {
806 Ok(g) => g,
807 Err(e) => return e.into_compile_error().into(),
808 };
809 let tags = gen_tags(&input.data, &input.attrs, &mut errors);
810 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
811 let errors = errors.into_iter().map(|e| e.into_compile_error());
812 let target = parse_for(&name, &input.attrs);
813 let output = quote! {
814 #(#errors)*
815
816 #[automatically_derived]
817 impl #impl_generics ::object_rainbow::Tagged for #target #ty_generics #where_clause {
818 const TAGS: ::object_rainbow::Tags = #tags;
819 }
820 };
821 TokenStream::from(output)
822}
823
824struct FieldTagArgs {
825 skip: bool,
826}
827
828impl Parse for FieldTagArgs {
829 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
830 let mut skip = false;
831 while !input.is_empty() {
832 let ident = input.parse::<Ident>()?;
833 if ident.to_string().as_str() != "skip" {
834 return Err(Error::new(ident.span(), "expected: skip"));
835 }
836 skip = true;
837 if !input.is_empty() {
838 input.parse::<Comma>()?;
839 }
840 }
841 Ok(Self { skip })
842 }
843}
844
845fn bounds_tagged(
846 mut generics: Generics,
847 data: &Data,
848 errors: &mut Vec<Error>,
849) -> syn::Result<Generics> {
850 let g = &bounds_g(&generics);
851 match data {
852 Data::Struct(data) => {
853 for f in data.fields.iter() {
854 let mut skip = false;
855 for attr in &f.attrs {
856 if attr_str(attr).as_deref() == Some("tags") {
857 match attr.parse_args::<FieldTagArgs>() {
858 Ok(args) => skip |= args.skip,
859 Err(e) => errors.push(e),
860 }
861 }
862 }
863 if !skip {
864 let ty = &f.ty;
865 if type_contains_generics(GContext { g, always: false }, ty) {
866 generics.make_where_clause().predicates.push(
867 parse_quote_spanned! { ty.span() =>
868 #ty: ::object_rainbow::Tagged
869 },
870 );
871 }
872 }
873 }
874 }
875 Data::Enum(data) => {
876 for v in data.variants.iter() {
877 for f in v.fields.iter() {
878 let mut skip = false;
879 for attr in &f.attrs {
880 if attr_str(attr).as_deref() == Some("tags") {
881 match attr.parse_args::<FieldTagArgs>() {
882 Ok(args) => skip |= args.skip,
883 Err(e) => errors.push(e),
884 }
885 }
886 }
887 if !skip {
888 let ty = &f.ty;
889 if type_contains_generics(GContext { g, always: false }, ty) {
890 generics.make_where_clause().predicates.push(
891 parse_quote_spanned! { ty.span() =>
892 #ty: ::object_rainbow::Tagged
893 },
894 );
895 }
896 }
897 }
898 }
899 }
900 Data::Union(data) => {
901 return Err(Error::new_spanned(
902 data.union_token,
903 "`union`s are not supported",
904 ));
905 }
906 }
907 Ok(generics)
908}
909
910struct StructTagArgs {
911 tags: Vec<LitStr>,
912}
913
914impl Parse for StructTagArgs {
915 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
916 let mut tags = Vec::new();
917 while !input.is_empty() {
918 let tag = input.parse::<LitStr>()?;
919 tags.push(tag);
920 if !input.is_empty() {
921 input.parse::<Comma>()?;
922 }
923 }
924 Ok(Self { tags })
925 }
926}
927
928fn fields_tags(fields: &syn::Fields) -> Vec<proc_macro2::TokenStream> {
929 fields
930 .iter()
931 .filter_map(|f| {
932 let mut skip = false;
933 for attr in &f.attrs {
934 if attr_str(attr).as_deref() == Some("tags") {
935 skip |= attr.parse_args::<FieldTagArgs>().ok()?.skip;
936 }
937 }
938 let ty = &f.ty;
939 (!skip).then_some(quote! { <#ty as ::object_rainbow::Tagged>::TAGS })
940 })
941 .collect()
942}
943
944fn gen_tags(data: &Data, attrs: &[Attribute], errors: &mut Vec<Error>) -> proc_macro2::TokenStream {
945 match data {
946 Data::Struct(data) => {
947 let mut tags = Vec::new();
948 for attr in attrs {
949 if attr_str(attr).as_deref() == Some("tags") {
950 match attr.parse_args::<StructTagArgs>() {
951 Ok(mut args) => tags.append(&mut args.tags),
952 Err(e) => errors.push(e),
953 }
954 }
955 }
956 let nested = fields_tags(&data.fields);
957 if nested.len() == 1 && tags.is_empty() {
958 let nested = nested.into_iter().next().unwrap();
959 quote! {
960 #nested
961 }
962 } else {
963 quote! {
964 ::object_rainbow::Tags(&[#(#tags),*], &[#(&#nested),*])
965 }
966 }
967 }
968 Data::Enum(data) => {
969 let mut tags = Vec::new();
970 for attr in attrs {
971 if attr_str(attr).as_deref() == Some("tags") {
972 match attr.parse_args::<StructTagArgs>() {
973 Ok(mut args) => tags.append(&mut args.tags),
974 Err(e) => errors.push(e),
975 }
976 }
977 }
978 let mut nested: Vec<_> = data
979 .variants
980 .iter()
981 .flat_map(|v| fields_tags(&v.fields))
982 .collect();
983 let kind_tags = quote! {
984 <
985 <
986 <
987 Self
988 as
989 ::object_rainbow::Enum
990 >::Kind
991 as
992 ::object_rainbow::enumkind::EnumKind
993 >::Tag
994 as ::object_rainbow::Tagged
995 >::TAGS
996 };
997 nested.insert(0, kind_tags);
998 if nested.len() == 1 && tags.is_empty() {
999 let nested = nested.into_iter().next().unwrap();
1000 quote! {
1001 #nested
1002 }
1003 } else {
1004 quote! {
1005 ::object_rainbow::Tags(&[#(#tags),*], &[#(&#nested),*])
1006 }
1007 }
1008 }
1009 Data::Union(data) => {
1010 Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1011 }
1012 }
1013}
1014
1015#[proc_macro_derive(Size)]
1037pub fn derive_size(input: TokenStream) -> TokenStream {
1038 let input = parse_macro_input!(input as DeriveInput);
1039 let name = input.ident;
1040 let size_arr = gen_size_arr(&input.data);
1041 let size = gen_size(&input.data);
1042 let (generics, is_enum) = match bounds_size(input.generics.clone(), &input.data, &size_arr) {
1043 Ok(g) => g,
1044 Err(e) => return e.into_compile_error().into(),
1045 };
1046 let (_, ty_generics, where_clause) = generics.split_for_impl();
1047 let mut generics = input.generics;
1048 if is_enum {
1049 generics.params.push(parse_quote!(
1050 __Output: ::object_rainbow::typenum::Unsigned
1051 ));
1052 }
1053 let (impl_generics, _, _) = generics.split_for_impl();
1054 let target = parse_for(&name, &input.attrs);
1055 let output = quote! {
1056 const _: () = {
1057 use ::object_rainbow::typenum::tarr;
1058
1059 #[automatically_derived]
1060 impl #impl_generics ::object_rainbow::Size for #target #ty_generics #where_clause {
1061 const SIZE: usize = #size;
1062
1063 type Size = <#size_arr as ::object_rainbow::typenum::FoldAdd>::Output;
1064 }
1065 };
1066 };
1067 TokenStream::from(output)
1068}
1069
1070fn bounds_size(
1071 mut generics: Generics,
1072 data: &Data,
1073 size_arr: &proc_macro2::TokenStream,
1074) -> syn::Result<(Generics, bool)> {
1075 let g = &bounds_g(&generics);
1076 let is_enum = match data {
1077 Data::Struct(data) => {
1078 for f in data.fields.iter() {
1079 let ty = &f.ty;
1080 if type_contains_generics(GContext { g, always: false }, ty) {
1081 generics.make_where_clause().predicates.push(
1082 parse_quote_spanned! { ty.span() =>
1083 #ty: ::object_rainbow::Size
1084 },
1085 );
1086 }
1087 }
1088 generics.make_where_clause().predicates.push(parse_quote!(
1089 #size_arr: ::object_rainbow::typenum::FoldAdd<
1090 Output: ::object_rainbow::typenum::Unsigned
1091 >
1092 ));
1093 false
1094 }
1095 Data::Enum(data) => {
1096 for v in data.variants.iter() {
1097 for f in v.fields.iter() {
1098 let ty = &f.ty;
1099 if type_contains_generics(GContext { g, always: false }, ty) {
1100 generics.make_where_clause().predicates.push(
1101 parse_quote_spanned! { ty.span() =>
1102 #ty: ::object_rainbow::Size
1103 },
1104 );
1105 }
1106 }
1107 }
1108 for v in data.variants.iter().skip(1) {
1109 let arr = fields_size_arr(&v.fields, true);
1110 generics.make_where_clause().predicates.push(parse_quote!(
1111 #arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
1112 ));
1113 }
1114 generics.make_where_clause().predicates.push(parse_quote!(
1115 #size_arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
1116 ));
1117 true
1118 }
1119 Data::Union(data) => {
1120 return Err(Error::new_spanned(
1121 data.union_token,
1122 "`union`s are not supported",
1123 ));
1124 }
1125 };
1126 Ok((generics, is_enum))
1127}
1128
1129fn fields_size_arr(fields: &syn::Fields, as_enum: bool) -> proc_macro2::TokenStream {
1130 let kind_size = quote! {
1131 <
1132 <
1133 <
1134 Self
1135 as
1136 ::object_rainbow::Enum
1137 >::Kind
1138 as
1139 ::object_rainbow::enumkind::EnumKind
1140 >::Tag
1141 as ::object_rainbow::Size
1142 >::Size
1143 };
1144 if fields.is_empty() {
1145 return if as_enum {
1146 quote! { tarr![#kind_size, ::object_rainbow::typenum::consts::U0] }
1147 } else {
1148 quote! { tarr![::object_rainbow::typenum::consts::U0] }
1149 };
1150 }
1151 let size_arr = fields.iter().map(|f| {
1152 let ty = &f.ty;
1153 quote! { <#ty as ::object_rainbow::Size>::Size }
1154 });
1155 if as_enum {
1156 quote! { tarr![#kind_size, ::object_rainbow::typenum::consts::U0, #(#size_arr),*] }
1157 } else {
1158 quote! { tarr![::object_rainbow::typenum::consts::U0, #(#size_arr),*] }
1159 }
1160}
1161
1162fn gen_size_arr(data: &Data) -> proc_macro2::TokenStream {
1163 match data {
1164 Data::Struct(data) => fields_size_arr(&data.fields, false),
1165 Data::Enum(data) => {
1166 if let Some(v) = data.variants.first() {
1167 fields_size_arr(&v.fields, true)
1168 } else {
1169 Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
1170 .into_compile_error()
1171 }
1172 }
1173 Data::Union(data) => {
1174 Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1175 }
1176 }
1177}
1178
1179fn fields_size(fields: &syn::Fields) -> proc_macro2::TokenStream {
1180 if fields.is_empty() {
1181 return quote! {0};
1182 }
1183 let size = fields.iter().map(|f| {
1184 let ty = &f.ty;
1185 quote! { <#ty as ::object_rainbow::Size>::SIZE }
1186 });
1187 quote! {
1188 #(#size)+*
1189 }
1190}
1191
1192fn gen_size(data: &Data) -> proc_macro2::TokenStream {
1193 match data {
1194 Data::Struct(data) => fields_size(&data.fields),
1195 Data::Enum(data) => {
1196 if let Some(v) = data.variants.first() {
1197 let size = fields_size(&v.fields);
1198 let kind_size = quote! {
1199 <
1200 <
1201 <
1202 Self
1203 as
1204 ::object_rainbow::Enum
1205 >::Kind
1206 as
1207 ::object_rainbow::enumkind::EnumKind
1208 >::Tag
1209 as ::object_rainbow::Size
1210 >::SIZE
1211 };
1212 quote! { #kind_size + #size }
1213 } else {
1214 Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
1215 .into_compile_error()
1216 }
1217 }
1218 Data::Union(data) => {
1219 Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1220 }
1221 }
1222}
1223
1224#[proc_macro_derive(Parse, attributes(parse))]
1245pub fn derive_parse(input: TokenStream) -> TokenStream {
1246 let input = parse_macro_input!(input as DeriveInput);
1247 let name = input.ident;
1248 let generics = input.generics.clone();
1249 let (_, ty_generics, _) = generics.split_for_impl();
1250 let (inp, generics) = match bounds_parse(input.generics, &input.data, &input.attrs) {
1251 Ok(g) => g,
1252 Err(e) => return e.into_compile_error().into(),
1253 };
1254 let (parse, enum_parse) = gen_parse(&input.data, &inp);
1255 let (impl_generics, _, where_clause) = generics.split_for_impl();
1256 let target = parse_for(&name, &input.attrs);
1257 let enum_parse = enum_parse.map(|enum_parse| {
1258 quote! {
1259 #[automatically_derived]
1260 impl #impl_generics ::object_rainbow::enumkind::EnumParse<#inp> for #target #ty_generics
1261 #where_clause
1262 {
1263 fn enum_parse(
1264 kind: <Self as ::object_rainbow::Enum>::Kind, mut input: #inp,
1265 ) -> ::object_rainbow::Result<Self> {
1266 #enum_parse
1267 }
1268 }
1269 }
1270 });
1271 let output = quote! {
1272 const _: () = {
1273 #[automatically_derived]
1274 impl #impl_generics ::object_rainbow::Parse<#inp> for #target #ty_generics
1275 #where_clause
1276 {
1277 fn parse(mut input: #inp) -> ::object_rainbow::Result<Self> {
1278 #parse
1279 }
1280 }
1281
1282 #enum_parse
1283 };
1284 };
1285 TokenStream::from(output)
1286}
1287
1288#[derive(Debug, FromMeta)]
1289#[darling(derive_syn_parse)]
1290struct ContainerParseArgs {
1291 #[darling(default)]
1292 unchecked: bool,
1293 #[darling(default)]
1294 bound: Option<LitStr>,
1295 #[darling(default)]
1296 generic: Option<LitStr>,
1297 #[darling(default)]
1298 input: Option<LitStr>,
1299}
1300
1301fn parse_parse_args(
1302 attrs: &[Attribute],
1303) -> syn::Result<(bool, Ident, Vec<WherePredicate>, Vec<GenericParam>)> {
1304 let mut u = false;
1305 let mut inp = parse_quote!(__I);
1306 let mut wheres = Vec::new();
1307 let mut ig = Vec::new();
1308 for attr in attrs {
1309 if attr_str(attr).as_deref() == Some("parse") {
1310 let ContainerParseArgs {
1311 unchecked,
1312 input,
1313 bound,
1314 generic,
1315 } = attr.parse_args()?;
1316 if unchecked {
1317 u = true;
1318 }
1319 if let Some(input) = input {
1320 inp = input.parse()?;
1321 }
1322 if let Some(bound) = bound {
1323 wheres.push(bound.parse()?);
1324 }
1325 if let Some(generic) = generic {
1326 ig.push(generic.parse()?);
1327 }
1328 }
1329 }
1330 Ok((u, inp, wheres, ig))
1331}
1332
1333#[derive(Debug, FromMeta)]
1334#[darling(derive_syn_parse)]
1335struct ParseArgs {
1336 bound: Option<Type>,
1337 #[darling(default)]
1338 unchecked: bool,
1339 with: Option<Expr>,
1340}
1341
1342fn bounds_parse(
1343 mut generics: Generics,
1344 data: &Data,
1345 attrs: &[Attribute],
1346) -> syn::Result<(Ident, Generics)> {
1347 let (recursive, _, _, _) = parse_recursive_inline(attrs)?;
1348 let (u, inp, wheres, ig) = parse_parse_args(attrs)?;
1349 let tr = |last| match (last, recursive) {
1350 (true, true) => {
1351 quote!(::object_rainbow::Parse<#inp> + ::object_rainbow::Object<#inp::Extra>)
1352 }
1353 (true, false) => quote!(::object_rainbow::Parse<#inp>),
1354 (false, true) => {
1355 quote!(::object_rainbow::ParseInline<#inp> + ::object_rainbow::Inline<#inp::Extra>)
1356 }
1357 (false, false) => quote!(::object_rainbow::ParseInline<#inp>),
1358 };
1359 match data {
1360 Data::Struct(data) => {
1361 let last_at = data.fields.len().saturating_sub(1);
1362 'field: for (i, f) in data.fields.iter().enumerate() {
1363 let last = i == last_at;
1364 let ty = &f.ty;
1365 let mut b = None;
1366 for attr in &f.attrs {
1367 if attr_str(attr).as_deref() == Some("parse") {
1368 let ParseArgs {
1369 bound, unchecked, ..
1370 } = attr.parse_args::<ParseArgs>()?;
1371 if unchecked {
1372 continue 'field;
1373 }
1374 if let Some(bound) = bound {
1375 b = Some(bound);
1376 }
1377 }
1378 }
1379 if let Some(bound) = b {
1380 generics.make_where_clause().predicates.push(
1381 parse_quote_spanned! { ty.span() =>
1382 (#ty, #inp::Extra): ::object_rainbow::BoundPair<
1383 T = #ty, E = #inp::Extra
1384 > + #bound
1385 },
1386 );
1387 } else {
1388 if u {
1389 continue 'field;
1390 }
1391 let tr = tr(last);
1392 generics.make_where_clause().predicates.push(
1393 parse_quote_spanned! { ty.span() =>
1394 #ty: #tr
1395 },
1396 );
1397 }
1398 }
1399 }
1400 Data::Enum(data) => {
1401 for v in data.variants.iter() {
1402 let last_at = v.fields.len().saturating_sub(1);
1403 'field: for (i, f) in v.fields.iter().enumerate() {
1404 let ty = &f.ty;
1405 let mut b = None;
1406 for attr in &f.attrs {
1407 if attr_str(attr).as_deref() == Some("parse") {
1408 let ParseArgs {
1409 bound, unchecked, ..
1410 } = attr.parse_args::<ParseArgs>()?;
1411 if unchecked {
1412 continue 'field;
1413 }
1414 if let Some(bound) = bound {
1415 b = Some(bound);
1416 }
1417 }
1418 }
1419 if let Some(bound) = b {
1420 generics.make_where_clause().predicates.push(
1421 parse_quote_spanned! { ty.span() =>
1422 (#ty, #inp::Extra): ::object_rainbow::BoundPair<
1423 T = #ty, E = #inp::Extra
1424 > + #bound
1425 },
1426 );
1427 } else {
1428 if u {
1429 continue 'field;
1430 }
1431 let last = i == last_at;
1432 let tr = tr(last);
1433 generics.make_where_clause().predicates.push(
1434 parse_quote_spanned! { ty.span() =>
1435 #ty: #tr
1436 },
1437 );
1438 }
1439 }
1440 }
1441 }
1442 Data::Union(data) => {
1443 return Err(Error::new_spanned(
1444 data.union_token,
1445 "`union`s are not supported",
1446 ));
1447 }
1448 }
1449 generics.params.push(if recursive {
1450 parse_quote!(#inp: ::object_rainbow::PointInput<
1451 Extra: ::core::marker::Send + ::core::marker::Sync + ::core::clone::Clone
1452 >)
1453 } else {
1454 parse_quote!(#inp: ::object_rainbow::ParseInput)
1455 });
1456 for bound in wheres {
1457 generics.make_where_clause().predicates.push(bound);
1458 }
1459 generics.params.extend(ig);
1460 Ok((inp, generics))
1461}
1462
1463fn gen_parse(
1464 data: &Data,
1465 inp: &Ident,
1466) -> (proc_macro2::TokenStream, Option<proc_macro2::TokenStream>) {
1467 match data {
1468 Data::Struct(data) => {
1469 let arm = fields_parse(&data.fields, inp);
1470 (quote! { Ok(Self #arm)}, None)
1471 }
1472 Data::Enum(data) => {
1473 let parse = data.variants.iter().map(|v| {
1474 let ident = &v.ident;
1475 let arm = fields_parse(&v.fields, inp);
1476 quote! {
1477 <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
1478 }
1479 });
1480 (
1481 quote! {
1482 ::object_rainbow::enumkind::EnumParse::parse_as_enum(input)
1483 },
1484 Some(quote! {
1485 Ok(match kind {
1486 #(#parse)*
1487 })
1488 }),
1489 )
1490 }
1491 Data::Union(data) => (
1492 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error(),
1493 None,
1494 ),
1495 }
1496}
1497
1498fn fields_parse(fields: &syn::Fields, inp: &Ident) -> proc_macro2::TokenStream {
1499 let last_at = fields.len().saturating_sub(1);
1500 match fields {
1501 syn::Fields::Named(fields) => {
1502 let parse = fields.named.iter().enumerate().map(|(i, f)| {
1503 let last = i == last_at;
1504 let ty = &f.ty;
1505 let mut w = None;
1506 let mut b = None;
1507 for attr in &f.attrs {
1508 if attr_str(attr).as_deref() == Some("parse") {
1509 let ParseArgs { with, bound, .. } = match attr.parse_args::<ParseArgs>() {
1510 Ok(args) => args,
1511 Err(e) => return e.into_compile_error(),
1512 };
1513 if let Some(with) = with {
1514 w = Some(with);
1515 }
1516 if let Some(bound) = bound {
1517 b = Some(bound);
1518 }
1519 }
1520 }
1521 let i = f.ident.as_ref().unwrap();
1522 if let Some(with) = w {
1523 let arg = if last {
1524 quote!(input)
1525 } else {
1526 quote!(&mut input)
1527 };
1528 if let Some(bound) = b {
1529 quote_spanned! { f.ty.span() =>
1530 #i: <(#ty, #inp::Extra) as #bound>::#with(#arg)?
1531 }
1532 } else {
1533 quote_spanned! { f.ty.span() =>
1534 #i: #with(#arg)?
1535 }
1536 }
1537 } else {
1538 let method = if last {
1539 quote!(parse)
1540 } else {
1541 quote!(parse_inline)
1542 };
1543 quote_spanned! { f.ty.span() =>
1544 #i: input.#method()?
1545 }
1546 }
1547 });
1548 quote! { { #(#parse),* } }
1549 }
1550 syn::Fields::Unnamed(fields) => {
1551 let parse = fields.unnamed.iter().enumerate().map(|(i, f)| {
1552 let ty = &f.ty;
1553 let mut w = None;
1554 let mut b = None;
1555 for attr in &f.attrs {
1556 if attr_str(attr).as_deref() == Some("parse") {
1557 let ParseArgs { with, bound, .. } = match attr.parse_args::<ParseArgs>() {
1558 Ok(args) => args,
1559 Err(e) => return e.into_compile_error(),
1560 };
1561 if let Some(with) = with {
1562 w = Some(with);
1563 }
1564 if let Some(bound) = bound {
1565 b = Some(bound);
1566 }
1567 }
1568 }
1569 let last = i == last_at;
1570 if let Some(with) = w {
1571 let arg = if last {
1572 quote!(input)
1573 } else {
1574 quote!(&mut input)
1575 };
1576 if let Some(bound) = b {
1577 quote_spanned! { f.ty.span() =>
1578 <(#ty, #inp::Extra) as #bound>::#with(#arg)?
1579 }
1580 } else {
1581 quote_spanned! { f.ty.span() =>
1582 #with(#arg)?
1583 }
1584 }
1585 } else {
1586 let method = if last {
1587 quote!(parse)
1588 } else {
1589 quote!(parse_inline)
1590 };
1591 quote_spanned! { f.ty.span() =>
1592 input.#method()?
1593 }
1594 }
1595 });
1596 quote! { (#(#parse),*) }
1597 }
1598 syn::Fields::Unit => quote! {},
1599 }
1600}
1601
1602#[proc_macro_derive(ParseInline, attributes(parse))]
1623pub fn derive_parse_inline(input: TokenStream) -> TokenStream {
1624 let input = parse_macro_input!(input as DeriveInput);
1625 let name = input.ident;
1626 let generics = input.generics.clone();
1627 let (_, ty_generics, _) = generics.split_for_impl();
1628 let (inp, generics) = match bounds_parse_inline(input.generics, &input.data, &input.attrs) {
1629 Ok(g) => g,
1630 Err(e) => return e.into_compile_error().into(),
1631 };
1632 let (parse_inline, enum_parse_inline) = gen_parse_inline(&input.data);
1633 let (impl_generics, _, where_clause) = generics.split_for_impl();
1634 let target = parse_for(&name, &input.attrs);
1635 let enum_parse_inline = enum_parse_inline.map(|enum_parse_inline| {
1636 quote! {
1637 #[automatically_derived]
1638 impl #impl_generics ::object_rainbow::enumkind::EnumParseInline<#inp>
1639 for #target #ty_generics #where_clause {
1640 fn enum_parse_inline(
1641 kind: <Self as ::object_rainbow::Enum>::Kind, input: &mut #inp,
1642 ) -> ::object_rainbow::Result<Self> {
1643 #enum_parse_inline
1644 }
1645 }
1646 }
1647 });
1648 let output = quote! {
1649 #[automatically_derived]
1650 impl #impl_generics ::object_rainbow::ParseInline<#inp>
1651 for #target #ty_generics #where_clause {
1652 fn parse_inline(input: &mut #inp) -> ::object_rainbow::Result<Self> {
1653 #parse_inline
1654 }
1655 }
1656
1657 #enum_parse_inline
1658 };
1659 TokenStream::from(output)
1660}
1661
1662fn bounds_parse_inline(
1663 mut generics: Generics,
1664 data: &Data,
1665 attrs: &[Attribute],
1666) -> syn::Result<(Ident, Generics)> {
1667 let (recursive, _, _, _) = parse_recursive_inline(attrs)?;
1668 let (u, inp, wheres, ig) = parse_parse_args(attrs)?;
1669 let tr = if recursive {
1670 quote!(::object_rainbow::ParseInline<#inp> + ::object_rainbow::Inline<#inp::Extra>)
1671 } else {
1672 quote!(::object_rainbow::ParseInline<#inp>)
1673 };
1674 match data {
1675 Data::Struct(data) => {
1676 'field: for f in data.fields.iter() {
1677 let ty = &f.ty;
1678 let mut b = None;
1679 for attr in &f.attrs {
1680 if attr_str(attr).as_deref() == Some("parse") {
1681 let ParseArgs {
1682 bound, unchecked, ..
1683 } = attr.parse_args::<ParseArgs>()?;
1684 if unchecked {
1685 continue 'field;
1686 }
1687 if let Some(bound) = bound {
1688 b = Some(bound);
1689 }
1690 }
1691 }
1692 if let Some(bound) = b {
1693 generics.make_where_clause().predicates.push(
1694 parse_quote_spanned! { ty.span() =>
1695 (#ty, #inp::Extra): #bound
1696 },
1697 );
1698 } else {
1699 if u {
1700 continue 'field;
1701 }
1702 generics.make_where_clause().predicates.push(
1703 parse_quote_spanned! { ty.span() =>
1704 #ty: #tr
1705 },
1706 );
1707 }
1708 }
1709 }
1710 Data::Enum(data) => {
1711 for v in data.variants.iter() {
1712 'field: for f in v.fields.iter() {
1713 let ty = &f.ty;
1714 let mut b = None;
1715 for attr in &f.attrs {
1716 if attr_str(attr).as_deref() == Some("parse") {
1717 let ParseArgs {
1718 bound, unchecked, ..
1719 } = attr.parse_args::<ParseArgs>()?;
1720 if unchecked {
1721 continue 'field;
1722 }
1723 if let Some(bound) = bound {
1724 b = Some(bound);
1725 }
1726 }
1727 }
1728 if let Some(bound) = b {
1729 generics.make_where_clause().predicates.push(
1730 parse_quote_spanned! { ty.span() =>
1731 (#ty, #inp::Extra): #bound
1732 },
1733 );
1734 } else {
1735 if u {
1736 continue 'field;
1737 }
1738 generics.make_where_clause().predicates.push(
1739 parse_quote_spanned! { ty.span() =>
1740 #ty: #tr
1741 },
1742 );
1743 }
1744 }
1745 }
1746 }
1747 Data::Union(data) => {
1748 return Err(Error::new_spanned(
1749 data.union_token,
1750 "`union`s are not supported",
1751 ));
1752 }
1753 }
1754 generics.params.push(if recursive {
1755 parse_quote!(#inp: ::object_rainbow::PointInput<
1756 Extra: ::core::marker::Send + ::core::marker::Sync
1757 >)
1758 } else {
1759 parse_quote!(#inp: ::object_rainbow::ParseInput)
1760 });
1761 for bound in wheres {
1762 generics.make_where_clause().predicates.push(bound);
1763 }
1764 for generic in ig {
1765 generics.params.push(parse_quote!(#generic));
1766 }
1767 Ok((inp, generics))
1768}
1769
1770fn fields_parse_inline(fields: &syn::Fields) -> proc_macro2::TokenStream {
1771 match fields {
1772 syn::Fields::Named(fields) => {
1773 let parse = fields.named.iter().map(|f| {
1774 let i = f.ident.as_ref().unwrap();
1775 quote_spanned! { f.ty.span() =>
1776 #i: input.parse_inline()?
1777 }
1778 });
1779 quote! { { #(#parse),* } }
1780 }
1781 syn::Fields::Unnamed(fields) => {
1782 let parse = fields.unnamed.iter().map(|f| {
1783 quote_spanned! { f.ty.span() =>
1784 input.parse_inline()?
1785 }
1786 });
1787 quote! { (#(#parse),*) }
1788 }
1789 syn::Fields::Unit => quote! {},
1790 }
1791}
1792
1793fn gen_parse_inline(data: &Data) -> (proc_macro2::TokenStream, Option<proc_macro2::TokenStream>) {
1794 match data {
1795 Data::Struct(data) => {
1796 let arm = fields_parse_inline(&data.fields);
1797 (quote! { Ok(Self #arm) }, None)
1798 }
1799 Data::Enum(data) => {
1800 let parse_inline = data.variants.iter().map(|v| {
1801 let ident = &v.ident;
1802 let arm = fields_parse_inline(&v.fields);
1803 quote! {
1804 <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
1805 }
1806 });
1807 (
1808 quote! {
1809 ::object_rainbow::enumkind::EnumParseInline::parse_as_inline_enum(input)
1810 },
1811 Some(quote! {
1812 Ok(match kind {
1813 #(#parse_inline)*
1814 })
1815 }),
1816 )
1817 }
1818 Data::Union(data) => (
1819 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error(),
1820 None,
1821 ),
1822 }
1823}
1824
1825#[proc_macro_derive(ParseAsInline)]
1842pub fn derive_parse_as_inline(input: TokenStream) -> TokenStream {
1843 let input = parse_macro_input!(input as DeriveInput);
1844 let name = input.ident;
1845 let generics = input.generics.clone();
1846 let (_, ty_generics, _) = generics.split_for_impl();
1847 let generics = match bounds_parse_as_inline(input.generics, &name) {
1848 Ok(g) => g,
1849 Err(e) => return e.into_compile_error().into(),
1850 };
1851 let (impl_generics, _, where_clause) = generics.split_for_impl();
1852 let target = parse_for(&name, &input.attrs);
1853 let output = quote! {
1854 #[automatically_derived]
1855 impl #impl_generics ::object_rainbow::Parse<__I> for #target #ty_generics #where_clause {
1856 fn parse(input: __I) -> ::object_rainbow::Result<Self> {
1857 ::object_rainbow::ParseInline::<__I>::parse_as_inline(input)
1858 }
1859 }
1860 };
1861 TokenStream::from(output)
1862}
1863
1864fn bounds_parse_as_inline(mut generics: Generics, name: &Ident) -> syn::Result<Generics> {
1865 generics
1866 .make_where_clause()
1867 .predicates
1868 .push(parse_quote_spanned! { name.span() =>
1869 Self: ::object_rainbow::ParseInline::<__I>
1870 });
1871 generics
1872 .params
1873 .push(parse_quote!(__I: ::object_rainbow::ParseInput));
1874 Ok(generics)
1875}
1876
1877fn parse_path(attr: &Attribute) -> syn::Result<Type> {
1878 attr.parse_args::<LitStr>()?.parse()
1879}
1880
1881fn attr_str(attr: &Attribute) -> Option<String> {
1882 Some(attr.path().get_ident()?.to_string())
1883}
1884
1885#[proc_macro_derive(Enum, attributes(enumtag))]
1945pub fn derive_enum(input: TokenStream) -> TokenStream {
1946 let input = parse_macro_input!(input as DeriveInput);
1947 let name = input.ident;
1948 let generics = input.generics.clone();
1949 let (_, ty_generics, _) = generics.split_for_impl();
1950 let generics = input.generics;
1951 let length = gen_length(&input.data);
1952 let variants = gen_variants(&input.data);
1953 let variant_count = gen_variant_count(&input.data);
1954 let to_tag = gen_to_tag(&input.data);
1955 let from_tag = gen_from_tag(&input.data);
1956 let kind = gen_kind(&input.data);
1957 let (impl_generics, _, where_clause) = generics.split_for_impl();
1958 let mut errors = Vec::new();
1959 let mut enumtag = None;
1960 for attr in &input.attrs {
1961 if attr_str(attr).as_deref() == Some("enumtag") {
1962 match parse_path(attr) {
1963 Ok(path) => {
1964 if enumtag.is_some() {
1965 errors.push(Error::new_spanned(path, "duplicate tag"));
1966 } else {
1967 enumtag = Some(path);
1968 }
1969 }
1970 Err(e) => errors.push(e),
1971 }
1972 }
1973 }
1974 let enumtag = enumtag.unwrap_or_else(|| {
1975 parse_quote!(
1976 ::object_rainbow::partial_byte_tag::PartialByteTag<#length>
1977 )
1978 });
1979 let errors = errors.into_iter().map(|e| e.into_compile_error());
1980 let target = parse_for(&name, &input.attrs);
1981 let output = quote! {
1982 const _: () = {
1983 #(#errors)*
1984
1985 use ::object_rainbow::enumkind::EnumKind;
1986
1987 #[derive(Clone, Copy, ::object_rainbow::ParseAsInline)]
1988 pub enum __Kind {
1989 #variants
1990 }
1991
1992 #[automatically_derived]
1993 impl ::object_rainbow::enumkind::EnumKind for __Kind {
1994 type Tag = ::object_rainbow::enumkind::EnumTag<
1995 #enumtag,
1996 #variant_count,
1997 >;
1998
1999 fn to_tag(self) -> Self::Tag {
2000 #to_tag
2001 }
2002
2003 fn from_tag(tag: Self::Tag) -> Self {
2004 #from_tag
2005 }
2006 }
2007
2008 impl<I: ::object_rainbow::ParseInput> ::object_rainbow::ParseInline<I> for __Kind {
2009 fn parse_inline(input: &mut I) -> ::object_rainbow::Result<Self> {
2010 Ok(::object_rainbow::enumkind::EnumKind::from_tag(input.parse_inline()?))
2011 }
2012 }
2013
2014 #[automatically_derived]
2015 impl #impl_generics ::object_rainbow::Enum for #target #ty_generics #where_clause {
2016 type Kind = __Kind;
2017
2018 fn kind(&self) -> Self::Kind {
2019 #kind
2020 }
2021 }
2022 };
2023 };
2024 TokenStream::from(output)
2025}
2026
2027fn gen_length(data: &Data) -> proc_macro2::TokenStream {
2028 match data {
2029 Data::Struct(data) => {
2030 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2031 }
2032 Data::Enum(data) => {
2033 let name = format!("U{}", data.variants.len());
2034 let ident = Ident::new(&name, data.variants.span());
2035 quote! { ::object_rainbow::typenum::#ident }
2036 }
2037 Data::Union(data) => {
2038 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2039 }
2040 }
2041}
2042
2043fn gen_variants(data: &Data) -> proc_macro2::TokenStream {
2044 match data {
2045 Data::Struct(data) => {
2046 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2047 }
2048 Data::Enum(data) => {
2049 let variants = data.variants.iter().map(|v| &v.ident);
2050 quote! { #(#variants),* }
2051 }
2052 Data::Union(data) => {
2053 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2054 }
2055 }
2056}
2057
2058fn gen_variant_count(data: &Data) -> proc_macro2::TokenStream {
2059 match data {
2060 Data::Struct(data) => {
2061 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2062 }
2063 Data::Enum(data) => {
2064 let variant_count = data.variants.len();
2065 quote! { #variant_count }
2066 }
2067 Data::Union(data) => {
2068 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2069 }
2070 }
2071}
2072
2073fn gen_to_tag(data: &Data) -> proc_macro2::TokenStream {
2074 match data {
2075 Data::Struct(data) => {
2076 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2077 }
2078 Data::Enum(data) => {
2079 let to_tag = data.variants.iter().enumerate().map(|(i, v)| {
2080 let ident = &v.ident;
2081 quote_spanned! { ident.span() =>
2082 Self::#ident => ::object_rainbow::enumkind::EnumTag::from_const::<#i>(),
2083 }
2084 });
2085 quote! {
2086 match self {
2087 #(#to_tag)*
2088 }
2089 }
2090 }
2091 Data::Union(data) => {
2092 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2093 }
2094 }
2095}
2096
2097fn gen_from_tag(data: &Data) -> proc_macro2::TokenStream {
2098 match data {
2099 Data::Struct(data) => {
2100 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2101 }
2102 Data::Enum(data) => {
2103 let from_tag = data.variants.iter().enumerate().map(|(i, v)| {
2104 let ident = &v.ident;
2105 quote_spanned! { ident.span() =>
2106 #i => Self::#ident,
2107 }
2108 });
2109 quote! {
2110 match tag.to_usize() {
2111 #(#from_tag)*
2112 _ => unreachable!(),
2113 }
2114 }
2115 }
2116 Data::Union(data) => {
2117 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2118 }
2119 }
2120}
2121
2122fn gen_kind(data: &Data) -> proc_macro2::TokenStream {
2123 match data {
2124 Data::Struct(data) => {
2125 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2126 }
2127 Data::Enum(data) => {
2128 let variants = data.variants.iter().map(|v| {
2129 let ident = &v.ident;
2130 quote_spanned! { ident.span() =>
2131 Self::#ident {..} => __Kind::#ident,
2132 }
2133 });
2134 quote! {
2135 match self {
2136 #(#variants)*
2137 }
2138 }
2139 }
2140 Data::Union(data) => {
2141 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2142 }
2143 }
2144}
2145
2146#[proc_macro_derive(MaybeHasNiche)]
2159pub fn derive_maybe_has_niche(input: TokenStream) -> TokenStream {
2160 let input = parse_macro_input!(input as DeriveInput);
2161 let name = input.ident;
2162 let mn_array = gen_mn_array(&input.data);
2163 let (_, ty_generics, _) = input.generics.split_for_impl();
2164 let generics = match bounds_maybe_has_niche(input.generics.clone(), &input.data) {
2165 Ok(g) => g,
2166 Err(e) => return e.into_compile_error().into(),
2167 };
2168 let (impl_generics, _, where_clause) = generics.split_for_impl();
2169 let target = parse_for(&name, &input.attrs);
2170 let output = quote! {
2171 const _: () = {
2172 use ::object_rainbow::typenum::tarr;
2173
2174 #[automatically_derived]
2175 impl #impl_generics ::object_rainbow::MaybeHasNiche
2176 for #target #ty_generics #where_clause {
2177 type MnArray = #mn_array;
2178 }
2179 };
2180 };
2181 TokenStream::from(output)
2182}
2183
2184fn bounds_maybe_has_niche(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
2185 match data {
2186 Data::Struct(data) => {
2187 for f in data.fields.iter() {
2188 let ty = &f.ty;
2189 generics
2190 .make_where_clause()
2191 .predicates
2192 .push(parse_quote_spanned! { ty.span() =>
2193 #ty: ::object_rainbow::MaybeHasNiche<
2194 MnArray: ::object_rainbow::MnArray<
2195 MaybeNiche: ::object_rainbow::MaybeNiche
2196 >
2197 >
2198 });
2199 }
2200 }
2201 Data::Enum(data) => {
2202 generics.params.push(parse_quote!(
2203 __N: ::object_rainbow::typenum::Unsigned
2204 ));
2205 for (i, v) in data.variants.iter().enumerate() {
2206 let mn_array = fields_mn_array(&v.fields, Some(i));
2207 generics
2208 .make_where_clause()
2209 .predicates
2210 .push(parse_quote_spanned! { v.span() =>
2211 #mn_array: ::object_rainbow::MnArray<
2212 MaybeNiche: ::object_rainbow::NicheOr<N = __N>
2213 >
2214 });
2215 for f in v.fields.iter() {
2216 let ty = &f.ty;
2217 generics.make_where_clause().predicates.push(
2218 parse_quote_spanned! { ty.span() =>
2219 #ty: ::object_rainbow::MaybeHasNiche<
2220 MnArray: ::object_rainbow::MnArray<
2221 MaybeNiche: ::object_rainbow::MaybeNiche
2222 >
2223 >
2224 },
2225 );
2226 }
2227 }
2228 }
2229 Data::Union(data) => {
2230 return Err(Error::new_spanned(
2231 data.union_token,
2232 "`union`s are not supported",
2233 ));
2234 }
2235 }
2236 Ok(generics)
2237}
2238
2239fn fields_mn_array(fields: &syn::Fields, variant: Option<usize>) -> proc_macro2::TokenStream {
2240 let mn_array = fields.iter().map(|f| {
2241 let ty = &f.ty;
2242 quote! {
2243 <
2244 <
2245 #ty
2246 as
2247 ::object_rainbow::MaybeHasNiche
2248 >::MnArray
2249 as
2250 ::object_rainbow::MnArray
2251 >::MaybeNiche
2252 }
2253 });
2254 if let Some(variant) = variant {
2255 let kind_niche = quote! {
2256 ::object_rainbow::AutoEnumNiche<Self, #variant>
2257 };
2258 quote! {
2259 tarr![
2260 #kind_niche,
2261 ::object_rainbow::NoNiche<::object_rainbow::HackNiche<#variant>>, #(#mn_array),*
2262 ]
2263 }
2264 } else {
2265 quote! { tarr![#(#mn_array),*] }
2266 }
2267}
2268
2269fn gen_mn_array(data: &Data) -> proc_macro2::TokenStream {
2270 match data {
2271 Data::Struct(data) => fields_mn_array(&data.fields, None),
2272 Data::Enum(data) => {
2273 let mn_array = data.variants.iter().enumerate().map(|(i, v)| {
2274 let mn_array = fields_mn_array(&v.fields, Some(i));
2275 quote! { <#mn_array as ::object_rainbow::MnArray>::MaybeNiche }
2276 });
2277 quote! {
2278 ::object_rainbow::NicheFoldOrArray<tarr![#(#mn_array),*]>
2279 }
2280 }
2281 Data::Union(data) => {
2282 Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
2283 }
2284 }
2285}
2286
2287#[proc_macro_attribute]
2288pub fn derive_for_wrapped(args: TokenStream, input: TokenStream) -> TokenStream {
2289 let input = parse_macro_input!(input as ItemTrait);
2290 let sup = if args.is_empty() {
2291 let sup = input.supertraits.clone();
2292 quote!(#sup)
2293 } else {
2294 args.into()
2295 };
2296 let name = input.ident.clone();
2297 let generics = input.generics.clone();
2298 let (_, ty_generics, _) = generics.split_for_impl();
2299 let mut derived = Vec::new();
2300 for (path, extra) in [
2301 (
2302 quote!(map_extra::MappedExtra),
2303 vec![(quote!(__M), quote!(#sup))],
2304 ),
2305 (quote!(length_prefixed::Lp), vec![]),
2306 ] {
2307 let mut generics = input.generics.clone();
2308 generics.params.push(parse_quote! {
2309 __T: #name #ty_generics
2310 });
2311 for (i, ty) in &extra {
2312 generics.params.push(parse_quote! {
2313 #i: #ty
2314 });
2315 }
2316 let (impl_generics, _, where_clause) = generics.split_for_impl();
2317 let i = input
2318 .items
2319 .clone()
2320 .into_iter()
2321 .map(|i| match i {
2322 TraitItem::Const(i) => ImplItem::Const({
2323 let const_token = i.const_token;
2324 let ident = i.ident;
2325 let colon_token = i.colon_token;
2326 let ty = i.ty;
2327 let semi_token = i.semi_token;
2328 parse_quote! {
2329 #const_token
2330 #ident
2331 #colon_token
2332 #ty
2333 =
2334 <__T as #name #ty_generics>::#ident
2335 #semi_token
2336 }
2337 }),
2338 TraitItem::Fn(i) => ImplItem::Fn({
2339 let mut sig = i.sig;
2340 let ident = sig.ident.clone();
2341 let args = sig
2342 .inputs
2343 .iter_mut()
2344 .enumerate()
2345 .map(|(n, i)| match i {
2346 FnArg::Receiver(receiver) => {
2347 let reference = receiver.reference.as_ref().map(|(and, _)| and);
2348 let mutability = receiver.mutability.as_ref();
2349 let ident = &receiver.self_token;
2350 quote!(#reference #mutability *#ident)
2351 }
2352 FnArg::Typed(pat_type) => {
2353 let ident = Ident::new(&format!("arg{n}"), pat_type.span());
2354 *pat_type.pat = parse_quote!(#ident);
2355 quote!(#ident)
2356 }
2357 })
2358 .collect::<Vec<_>>();
2359 parse_quote! {
2360 #sig
2361 {
2362 <__T as #name #ty_generics>::#ident(
2363 #(#args),*
2364 )
2365 }
2366 }
2367 }),
2368 TraitItem::Type(i) => ImplItem::Type({
2369 let type_token = i.type_token;
2370 let ident = i.ident;
2371 let semi_token = i.semi_token;
2372 parse_quote! {
2373 #type_token
2374 #ident
2375 =
2376 <__T as #name #ty_generics>::#ident
2377 #semi_token
2378 }
2379 }),
2380 _ => unimplemented!("unknown/unsupported item"),
2381 })
2382 .collect::<Vec<_>>();
2383 let extra = extra.into_iter().map(|(k, _)| k);
2384 derived.push(quote! {
2385 impl #impl_generics #name #ty_generics for ::object_rainbow::#path<
2386 __T,
2387 #(#extra),*
2388 >
2389 #where_clause
2390 {
2391 #(#i)*
2392 }
2393 });
2394 }
2395 let output = quote! {
2396 #input
2397
2398 #(#derived)*
2399 };
2400 output.into()
2401}