1use std::collections::BTreeSet;
4
5use darling::{FromMeta, util::SpannedValue};
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, 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 #[darling(default)]
37 untagged: SpannedValue<bool>,
38}
39
40fn parse_for(name: &Ident, attrs: &[Attribute]) -> proc_macro2::TokenStream {
41 for attr in attrs {
42 if attr_str(attr).as_deref() == Some("rainbow") {
43 match attr.parse_args::<RainbowArgs>() {
44 Ok(RainbowArgs { remote, .. }) => {
45 if let Some(remote) = remote {
46 return remote.to_token_stream();
47 }
48 }
49 Err(e) => return e.into_compile_error(),
50 }
51 }
52 }
53 name.to_token_stream()
54}
55
56fn parse_untagged(attrs: &[Attribute]) -> syn::Result<Option<SpannedValue<bool>>> {
57 let mut u = None;
58 for attr in attrs {
59 if attr_str(attr).as_deref() == Some("rainbow") {
60 let RainbowArgs { untagged, .. } = attr.parse_args()?;
61 if *untagged {
62 u = Some(untagged);
63 }
64 }
65 }
66 Ok(u)
67}
68
69#[proc_macro_derive(ToOutput, attributes(rainbow))]
89pub fn derive_to_output(input: TokenStream) -> TokenStream {
90 let input = parse_macro_input!(input as DeriveInput);
91 let name = input.ident;
92 let generics = match bounds_to_output(input.generics, &input.data) {
93 Ok(g) => g,
94 Err(e) => return e.into_compile_error().into(),
95 };
96 let to_output = gen_to_output(&input.data, &input.attrs);
97 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
98 let target = parse_for(&name, &input.attrs);
99 let output = quote! {
100 #[automatically_derived]
101 impl #impl_generics ::object_rainbow::ToOutput for #target #ty_generics #where_clause {
102 fn to_output(&self, output: &mut impl ::object_rainbow::Output) {
103 #to_output
104 }
105 }
106 };
107 TokenStream::from(output)
108}
109
110fn bounds_to_output(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
111 let g = &bounds_g(&generics);
112 match data {
113 Data::Struct(data) => {
114 let last_at = data.fields.len().saturating_sub(1);
115 for (i, f) in data.fields.iter().enumerate() {
116 let last = i == last_at;
117 let ty = &f.ty;
118 let tr = if last {
119 quote!(::object_rainbow::ToOutput)
120 } else {
121 quote!(::object_rainbow::InlineOutput)
122 };
123 if !last || type_contains_generics(GContext { g, always: false }, ty) {
124 generics.make_where_clause().predicates.push(
125 parse_quote_spanned! { ty.span() =>
126 #ty: #tr
127 },
128 );
129 }
130 }
131 }
132 Data::Enum(data) => {
133 for v in data.variants.iter() {
134 let last_at = v.fields.len().saturating_sub(1);
135 for (i, f) in v.fields.iter().enumerate() {
136 let last = i == last_at;
137 let ty = &f.ty;
138 let tr = if last {
139 quote!(::object_rainbow::ToOutput)
140 } else {
141 quote!(::object_rainbow::InlineOutput)
142 };
143 if !last || type_contains_generics(GContext { g, always: false }, ty) {
144 generics.make_where_clause().predicates.push(
145 parse_quote_spanned! { ty.span() =>
146 #ty: #tr
147 },
148 );
149 }
150 }
151 }
152 }
153 Data::Union(data) => {
154 return Err(Error::new_spanned(
155 data.union_token,
156 "`union`s are not supported",
157 ));
158 }
159 }
160 Ok(generics)
161}
162
163fn fields_to_output(fields: &syn::Fields) -> proc_macro2::TokenStream {
164 match fields {
165 syn::Fields::Named(fields) => {
166 let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
167 let to_output = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
168 quote_spanned! { f.ty.span() =>
169 #i.to_output(output)
170 }
171 });
172 quote! {
173 { #(#let_self),* } => {
174 #(#to_output);*
175 }
176 }
177 }
178 syn::Fields::Unnamed(fields) => {
179 let let_self = fields
180 .unnamed
181 .iter()
182 .enumerate()
183 .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
184 let to_output = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
185 quote_spanned! { f.ty.span() =>
186 #i.to_output(output)
187 }
188 });
189 quote! {
190 (#(#let_self),*) => {
191 #(#to_output);*
192 }
193 }
194 }
195 syn::Fields::Unit => quote! {
196 => {}
197 },
198 }
199}
200
201fn gen_to_output(data: &Data, attrs: &[Attribute]) -> proc_macro2::TokenStream {
202 let untagged = match parse_untagged(attrs) {
203 Ok(untagged) => untagged,
204 Err(e) => return e.into_compile_error(),
205 };
206 match data {
207 Data::Struct(data) => {
208 let arm = fields_to_output(&data.fields);
209 quote! {
210 match self {
211 Self #arm
212 }
213 }
214 }
215 Data::Enum(data) => {
216 if data.variants.is_empty() {
217 return quote! {};
218 }
219 let to_output = data.variants.iter().map(|v| {
220 let ident = &v.ident;
221 let arm = fields_to_output(&v.fields);
222 quote! { Self::#ident #arm }
223 });
224 let tagged = if untagged.is_none() {
225 quote! {
226 let kind = ::object_rainbow::Enum::kind(self);
227 let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
228 tag.to_output(output);
229 }
230 } else {
231 quote! {}
232 };
233 quote! {
234 #tagged
235 match self {
236 #(#to_output)*
237 }
238 }
239 }
240 Data::Union(data) => {
241 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
242 }
243 }
244}
245
246#[proc_macro_derive(InlineOutput)]
266pub fn derive_inline_output(input: TokenStream) -> TokenStream {
267 let input = parse_macro_input!(input as DeriveInput);
268 let name = input.ident;
269 let generics = match bounds_inline_output(input.generics, &input.data) {
270 Ok(g) => g,
271 Err(e) => return e.into_compile_error().into(),
272 };
273 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
274 let target = parse_for(&name, &input.attrs);
275 let output = quote! {
276 #[automatically_derived]
277 impl #impl_generics ::object_rainbow::InlineOutput for #target #ty_generics #where_clause {}
278 };
279 TokenStream::from(output)
280}
281
282fn bounds_inline_output(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
283 match data {
284 Data::Struct(data) => {
285 for f in data.fields.iter() {
286 let ty = &f.ty;
287 generics
288 .make_where_clause()
289 .predicates
290 .push(parse_quote_spanned! { ty.span() =>
291 #ty: ::object_rainbow::InlineOutput
292 });
293 }
294 }
295 Data::Enum(data) => {
296 for v in data.variants.iter() {
297 for f in v.fields.iter() {
298 let ty = &f.ty;
299 generics.make_where_clause().predicates.push(
300 parse_quote_spanned! { ty.span() =>
301 #ty: ::object_rainbow::InlineOutput
302 },
303 );
304 }
305 }
306 }
307 Data::Union(data) => {
308 return Err(Error::new_spanned(
309 data.union_token,
310 "`union`s are not supported",
311 ));
312 }
313 }
314 Ok(generics)
315}
316
317#[proc_macro_derive(ListHashes, attributes(topology, rainbow))]
337pub fn derive_list_hashes(input: TokenStream) -> TokenStream {
338 let input = parse_macro_input!(input as DeriveInput);
339 let name = input.ident;
340 let generics = input.generics.clone();
341 let (_, ty_generics, _) = generics.split_for_impl();
342 let generics = match bounds_list_hashes(input.generics, &input.data) {
343 Ok(g) => g,
344 Err(e) => return e.into_compile_error().into(),
345 };
346 let list_hashes = gen_list_hashes(&input.data, &input.attrs);
347 let (impl_generics, _, where_clause) = generics.split_for_impl();
348 let target = parse_for(&name, &input.attrs);
349 let output = quote! {
350 #[automatically_derived]
351 impl #impl_generics ::object_rainbow::ListHashes for #target #ty_generics #where_clause {
352 fn list_hashes(&self, visitor: &mut impl FnMut(::object_rainbow::Hash)) {
353 #list_hashes
354 }
355 }
356 };
357 TokenStream::from(output)
358}
359
360fn bounds_list_hashes(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
361 let g = &bounds_g(&generics);
362 match data {
363 Data::Struct(data) => {
364 for f in data.fields.iter() {
365 let ty = &f.ty;
366 if type_contains_generics(GContext { g, always: false }, ty) {
367 generics.make_where_clause().predicates.push(
368 parse_quote_spanned! { ty.span() =>
369 #ty: ::object_rainbow::ListHashes
370 },
371 );
372 }
373 }
374 }
375 Data::Enum(data) => {
376 for v in data.variants.iter() {
377 for f in v.fields.iter() {
378 let ty = &f.ty;
379 if type_contains_generics(GContext { g, always: false }, ty) {
380 generics.make_where_clause().predicates.push(
381 parse_quote_spanned! { ty.span() =>
382 #ty: ::object_rainbow::ListHashes
383 },
384 );
385 }
386 }
387 }
388 }
389 Data::Union(data) => {
390 return Err(Error::new_spanned(
391 data.union_token,
392 "`union`s are not supported",
393 ));
394 }
395 }
396 Ok(generics)
397}
398
399fn fields_list_hashes(fields: &syn::Fields) -> proc_macro2::TokenStream {
400 match fields {
401 syn::Fields::Named(fields) => {
402 let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
403 let list_hashes = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
404 quote_spanned! { f.ty.span() =>
405 #i.list_hashes(visitor)
406 }
407 });
408 quote! {
409 { #(#let_self),* } => {
410 #(#list_hashes);*
411 }
412 }
413 }
414 syn::Fields::Unnamed(fields) => {
415 let let_self = fields
416 .unnamed
417 .iter()
418 .enumerate()
419 .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
420 let list_hashes = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
421 quote_spanned! { f.ty.span() =>
422 #i.list_hashes(visitor)
423 }
424 });
425 quote! {
426 (#(#let_self),*) => {
427 #(#list_hashes);*
428 }
429 }
430 }
431 syn::Fields::Unit => quote! {
432 => {}
433 },
434 }
435}
436
437fn gen_list_hashes(data: &Data, attrs: &[Attribute]) -> proc_macro2::TokenStream {
438 let untagged = match parse_untagged(attrs) {
439 Ok(untagged) => untagged,
440 Err(e) => return e.into_compile_error(),
441 };
442 match data {
443 Data::Struct(data) => {
444 let arm = fields_list_hashes(&data.fields);
445 quote! {
446 match self {
447 Self #arm
448 }
449 }
450 }
451 Data::Enum(data) => {
452 if data.variants.is_empty() {
453 return quote! {};
454 }
455 let to_output = data.variants.iter().map(|v| {
456 let ident = &v.ident;
457 let arm = fields_list_hashes(&v.fields);
458 quote! { Self::#ident #arm }
459 });
460 let tagged = if untagged.is_none() {
461 quote! {
462 let kind = ::object_rainbow::Enum::kind(self);
463 let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
464 tag.list_hashes(visitor);
465 }
466 } else {
467 quote! {}
468 };
469 quote! {
470 #tagged;
471 match self {
472 #(#to_output)*
473 }
474 }
475 }
476 Data::Union(data) => {
477 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
478 }
479 }
480}
481
482#[proc_macro_derive(Topological, attributes(topology))]
502pub fn derive_topological(input: TokenStream) -> TokenStream {
503 let input = parse_macro_input!(input as DeriveInput);
504 let name = input.ident;
505 let generics = input.generics.clone();
506 let (_, ty_generics, _) = generics.split_for_impl();
507 let generics = match bounds_topological(input.generics, &input.data, &input.attrs, &name) {
508 Ok(g) => g,
509 Err(e) => return e.into_compile_error().into(),
510 };
511 let traverse = gen_traverse(&input.data, &input.attrs);
512 let (impl_generics, _, where_clause) = generics.split_for_impl();
513 let target = parse_for(&name, &input.attrs);
514 let output = quote! {
515 const _: () = {
516 #[automatically_derived]
517 impl #impl_generics ::object_rainbow::Topological for #target #ty_generics
518 #where_clause
519 {
520 fn traverse(&self, visitor: &mut impl ::object_rainbow::PointVisitor) {
521 #traverse
522 }
523 }
524 };
525 };
526 TokenStream::from(output)
527}
528
529#[derive(Debug, FromMeta)]
530#[darling(derive_syn_parse)]
531struct ContainerTopologyArgs {
532 #[darling(default)]
533 recursive: bool,
534 #[darling(default)]
535 inline: bool,
536 #[darling(default)]
537 unchecked: bool,
538 #[darling(default)]
539 bound: Option<LitStr>,
540}
541
542fn parse_recursive_inline(
543 attrs: &[Attribute],
544) -> syn::Result<(bool, bool, bool, Vec<WherePredicate>)> {
545 let mut r = false;
546 let mut i = false;
547 let mut u = false;
548 let mut wheres = Vec::new();
549 for attr in attrs {
550 if attr_str(attr).as_deref() == Some("topology") {
551 let ContainerTopologyArgs {
552 recursive,
553 inline,
554 unchecked,
555 bound,
556 } = attr.parse_args()?;
557 if recursive {
558 r = true;
559 }
560 if inline {
561 i = true;
562 }
563 if unchecked {
564 u = true;
565 }
566 if let Some(bound) = bound {
567 wheres.push(bound.parse()?);
568 }
569 }
570 }
571 Ok((r, i, u, wheres))
572}
573
574#[derive(Debug, FromMeta)]
575#[darling(derive_syn_parse)]
576struct FieldTopologyArgs {
577 #[darling(default)]
578 unchecked: bool,
579 with: Option<Expr>,
580}
581
582fn bounds_topological(
583 mut generics: Generics,
584 data: &Data,
585 attrs: &[Attribute],
586 name: &Ident,
587) -> syn::Result<Generics> {
588 let (recursive, inline, u, wheres) = parse_recursive_inline(attrs)?;
589 let g = &bounds_g(&generics);
590 let bound = if recursive {
591 quote! { ::object_rainbow::Traversible }
592 } else {
593 quote! { ::object_rainbow::Topological }
594 };
595 match data {
596 Data::Struct(data) => {
597 'field: for f in data.fields.iter() {
598 let ty = &f.ty;
599 for attr in &f.attrs {
600 if attr_str(attr).as_deref() == Some("topology") {
601 let FieldTopologyArgs { unchecked, .. } = attr.parse_args()?;
602 if unchecked {
603 continue 'field;
604 }
605 }
606 }
607 if u {
608 continue 'field;
609 }
610 if type_contains_generics(GContext { g, always: false }, ty) {
611 generics.make_where_clause().predicates.push(
612 parse_quote_spanned! { ty.span() =>
613 #ty: #bound
614 },
615 );
616 }
617 }
618 }
619 Data::Enum(data) => {
620 for v in data.variants.iter() {
621 'field: for f in v.fields.iter() {
622 let ty = &f.ty;
623 for attr in &f.attrs {
624 if attr_str(attr).as_deref() == Some("topology") {
625 let FieldTopologyArgs { unchecked, .. } = attr.parse_args()?;
626 if unchecked {
627 continue 'field;
628 }
629 }
630 }
631 if u {
632 continue 'field;
633 }
634 if type_contains_generics(GContext { g, always: false }, ty) {
635 generics.make_where_clause().predicates.push(
636 parse_quote_spanned! { ty.span() =>
637 #ty: #bound
638 },
639 );
640 }
641 }
642 }
643 }
644 Data::Union(data) => {
645 return Err(Error::new_spanned(
646 data.union_token,
647 "`union`s are not supported",
648 ));
649 }
650 }
651 let output_bound = if inline {
652 quote! {
653 ::object_rainbow::InlineOutput
654 }
655 } else {
656 quote! {
657 ::object_rainbow::ToOutput
658 }
659 };
660 if recursive {
661 generics
662 .make_where_clause()
663 .predicates
664 .push(parse_quote_spanned! { name.span() =>
665 Self: #output_bound + ::object_rainbow::Tagged
666 });
667 }
668 for bound in wheres {
669 generics.make_where_clause().predicates.push(bound);
670 }
671 Ok(generics)
672}
673
674fn fields_traverse(fields: &syn::Fields) -> proc_macro2::TokenStream {
675 match fields {
676 syn::Fields::Named(fields) => {
677 let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
678 let traverse = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
679 let mut w = None;
680 for attr in &f.attrs {
681 if attr_str(attr).as_deref() == Some("topology") {
682 let FieldTopologyArgs { with, .. } = match attr.parse_args() {
683 Ok(args) => args,
684 Err(e) => return e.into_compile_error(),
685 };
686 if let Some(with) = with {
687 w = Some(with);
688 }
689 }
690 }
691 if let Some(with) = w {
692 quote_spanned! { f.ty.span() =>
693 #with(#i, visitor)
694 }
695 } else {
696 quote_spanned! { f.ty.span() =>
697 #i.traverse(visitor)
698 }
699 }
700 });
701 quote! {
702 { #(#let_self),* } => {
703 #(#traverse);*
704 }
705 }
706 }
707 syn::Fields::Unnamed(fields) => {
708 let let_self = fields
709 .unnamed
710 .iter()
711 .enumerate()
712 .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
713 let traverse = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
714 let mut w = None;
715 for attr in &f.attrs {
716 if attr_str(attr).as_deref() == Some("topology") {
717 let FieldTopologyArgs { with, .. } = match attr.parse_args() {
718 Ok(args) => args,
719 Err(e) => return e.into_compile_error(),
720 };
721 if let Some(with) = with {
722 w = Some(with);
723 }
724 }
725 }
726 if let Some(with) = w {
727 quote_spanned! { f.ty.span() =>
728 #with(#i, visitor)
729 }
730 } else {
731 quote_spanned! { f.ty.span() =>
732 #i.traverse(visitor)
733 }
734 }
735 });
736 quote! {
737 (#(#let_self),*) => {
738 #(#traverse);*
739 }
740 }
741 }
742 syn::Fields::Unit => quote! {
743 => {}
744 },
745 }
746}
747
748fn gen_traverse(data: &Data, attrs: &[Attribute]) -> proc_macro2::TokenStream {
749 let untagged = match parse_untagged(attrs) {
750 Ok(untagged) => untagged,
751 Err(e) => return e.into_compile_error(),
752 };
753 match data {
754 Data::Struct(data) => {
755 let arm = fields_traverse(&data.fields);
756 quote! {
757 match self {
758 Self #arm
759 }
760 }
761 }
762 Data::Enum(data) => {
763 if data.variants.is_empty() {
764 return quote! {};
765 }
766 let to_output = data.variants.iter().map(|v| {
767 let ident = &v.ident;
768 let arm = fields_traverse(&v.fields);
769 quote! { Self::#ident #arm }
770 });
771 let tagged = if untagged.is_none() {
772 quote! {
773 let kind = ::object_rainbow::Enum::kind(self);
774 let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
775 tag.traverse(visitor);
776 }
777 } else {
778 quote! {}
779 };
780 quote! {
781 #tagged;
782 match self {
783 #(#to_output)*
784 }
785 }
786 }
787 Data::Union(data) => {
788 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
789 }
790 }
791}
792
793#[proc_macro_derive(Tagged, attributes(tags))]
813pub fn derive_tagged(input: TokenStream) -> TokenStream {
814 let input = parse_macro_input!(input as DeriveInput);
815 let name = input.ident;
816 let mut errors = Vec::new();
817 let generics = match bounds_tagged(input.generics, &input.data, &mut errors) {
818 Ok(g) => g,
819 Err(e) => return e.into_compile_error().into(),
820 };
821 let tags = gen_tags(&input.data, &input.attrs, &mut errors);
822 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
823 let errors = errors.into_iter().map(|e| e.into_compile_error());
824 let target = parse_for(&name, &input.attrs);
825 let output = quote! {
826 #(#errors)*
827
828 #[automatically_derived]
829 impl #impl_generics ::object_rainbow::Tagged for #target #ty_generics #where_clause {
830 const TAGS: ::object_rainbow::Tags = #tags;
831 }
832 };
833 TokenStream::from(output)
834}
835
836struct FieldTagArgs {
837 skip: bool,
838}
839
840impl Parse for FieldTagArgs {
841 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
842 let mut skip = false;
843 while !input.is_empty() {
844 let ident = input.parse::<Ident>()?;
845 if ident.to_string().as_str() != "skip" {
846 return Err(Error::new(ident.span(), "expected: skip"));
847 }
848 skip = true;
849 if !input.is_empty() {
850 input.parse::<Comma>()?;
851 }
852 }
853 Ok(Self { skip })
854 }
855}
856
857fn bounds_tagged(
858 mut generics: Generics,
859 data: &Data,
860 errors: &mut Vec<Error>,
861) -> syn::Result<Generics> {
862 let g = &bounds_g(&generics);
863 match data {
864 Data::Struct(data) => {
865 for f in data.fields.iter() {
866 let mut skip = false;
867 for attr in &f.attrs {
868 if attr_str(attr).as_deref() == Some("tags") {
869 match attr.parse_args::<FieldTagArgs>() {
870 Ok(args) => skip |= args.skip,
871 Err(e) => errors.push(e),
872 }
873 }
874 }
875 if !skip {
876 let ty = &f.ty;
877 if type_contains_generics(GContext { g, always: false }, ty) {
878 generics.make_where_clause().predicates.push(
879 parse_quote_spanned! { ty.span() =>
880 #ty: ::object_rainbow::Tagged
881 },
882 );
883 }
884 }
885 }
886 }
887 Data::Enum(data) => {
888 for v in data.variants.iter() {
889 for f in v.fields.iter() {
890 let mut skip = false;
891 for attr in &f.attrs {
892 if attr_str(attr).as_deref() == Some("tags") {
893 match attr.parse_args::<FieldTagArgs>() {
894 Ok(args) => skip |= args.skip,
895 Err(e) => errors.push(e),
896 }
897 }
898 }
899 if !skip {
900 let ty = &f.ty;
901 if type_contains_generics(GContext { g, always: false }, ty) {
902 generics.make_where_clause().predicates.push(
903 parse_quote_spanned! { ty.span() =>
904 #ty: ::object_rainbow::Tagged
905 },
906 );
907 }
908 }
909 }
910 }
911 }
912 Data::Union(data) => {
913 return Err(Error::new_spanned(
914 data.union_token,
915 "`union`s are not supported",
916 ));
917 }
918 }
919 Ok(generics)
920}
921
922struct StructTagArgs {
923 tags: Vec<LitStr>,
924}
925
926impl Parse for StructTagArgs {
927 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
928 let mut tags = Vec::new();
929 while !input.is_empty() {
930 let tag = input.parse::<LitStr>()?;
931 tags.push(tag);
932 if !input.is_empty() {
933 input.parse::<Comma>()?;
934 }
935 }
936 Ok(Self { tags })
937 }
938}
939
940fn fields_tags(fields: &syn::Fields) -> Vec<proc_macro2::TokenStream> {
941 fields
942 .iter()
943 .filter_map(|f| {
944 let mut skip = false;
945 for attr in &f.attrs {
946 if attr_str(attr).as_deref() == Some("tags") {
947 skip |= attr.parse_args::<FieldTagArgs>().ok()?.skip;
948 }
949 }
950 let ty = &f.ty;
951 (!skip).then_some(quote! { <#ty as ::object_rainbow::Tagged>::TAGS })
952 })
953 .collect()
954}
955
956fn gen_tags(data: &Data, attrs: &[Attribute], errors: &mut Vec<Error>) -> proc_macro2::TokenStream {
957 let untagged = match parse_untagged(attrs) {
958 Ok(untagged) => untagged,
959 Err(e) => return e.into_compile_error(),
960 };
961 match data {
962 Data::Struct(data) => {
963 let mut tags = Vec::new();
964 for attr in attrs {
965 if attr_str(attr).as_deref() == Some("tags") {
966 match attr.parse_args::<StructTagArgs>() {
967 Ok(mut args) => tags.append(&mut args.tags),
968 Err(e) => errors.push(e),
969 }
970 }
971 }
972 let nested = fields_tags(&data.fields);
973 if nested.len() == 1 && tags.is_empty() {
974 let nested = nested.into_iter().next().unwrap();
975 quote! {
976 #nested
977 }
978 } else {
979 quote! {
980 ::object_rainbow::Tags(&[#(#tags),*], &[#(&#nested),*])
981 }
982 }
983 }
984 Data::Enum(data) => {
985 let mut tags = Vec::new();
986 for attr in attrs {
987 if attr_str(attr).as_deref() == Some("tags") {
988 match attr.parse_args::<StructTagArgs>() {
989 Ok(mut args) => tags.append(&mut args.tags),
990 Err(e) => errors.push(e),
991 }
992 }
993 }
994 let mut nested: Vec<_> = data
995 .variants
996 .iter()
997 .flat_map(|v| fields_tags(&v.fields))
998 .collect();
999 let kind_tags = quote! {
1000 <
1001 <
1002 <
1003 Self
1004 as
1005 ::object_rainbow::Enum
1006 >::Kind
1007 as
1008 ::object_rainbow::enumkind::EnumKind
1009 >::Tag
1010 as ::object_rainbow::Tagged
1011 >::TAGS
1012 };
1013 if untagged.is_none() {
1014 nested.insert(0, kind_tags);
1015 }
1016 if nested.len() == 1 && tags.is_empty() {
1017 let nested = nested.into_iter().next().unwrap();
1018 quote! {
1019 #nested
1020 }
1021 } else {
1022 quote! {
1023 ::object_rainbow::Tags(&[#(#tags),*], &[#(&#nested),*])
1024 }
1025 }
1026 }
1027 Data::Union(data) => {
1028 Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1029 }
1030 }
1031}
1032
1033#[proc_macro_derive(Size)]
1055pub fn derive_size(input: TokenStream) -> TokenStream {
1056 let input = parse_macro_input!(input as DeriveInput);
1057 let name = input.ident;
1058 let size_arr = gen_size_arr(&input.data);
1059 let size = gen_size(&input.data);
1060 let (generics, is_enum) = match bounds_size(input.generics.clone(), &input.data, &size_arr) {
1061 Ok(g) => g,
1062 Err(e) => return e.into_compile_error().into(),
1063 };
1064 let (_, ty_generics, where_clause) = generics.split_for_impl();
1065 let mut generics = input.generics;
1066 if is_enum {
1067 generics.params.push(parse_quote!(
1068 __Output: ::object_rainbow::typenum::Unsigned
1069 ));
1070 }
1071 let (impl_generics, _, _) = generics.split_for_impl();
1072 let target = parse_for(&name, &input.attrs);
1073 let output = quote! {
1074 const _: () = {
1075 use ::object_rainbow::typenum::tarr;
1076
1077 #[automatically_derived]
1078 impl #impl_generics ::object_rainbow::Size for #target #ty_generics #where_clause {
1079 const SIZE: usize = #size;
1080
1081 type Size = <#size_arr as ::object_rainbow::typenum::FoldAdd>::Output;
1082 }
1083 };
1084 };
1085 TokenStream::from(output)
1086}
1087
1088fn bounds_size(
1089 mut generics: Generics,
1090 data: &Data,
1091 size_arr: &proc_macro2::TokenStream,
1092) -> syn::Result<(Generics, bool)> {
1093 let g = &bounds_g(&generics);
1094 let is_enum = match data {
1095 Data::Struct(data) => {
1096 for f in data.fields.iter() {
1097 let ty = &f.ty;
1098 if type_contains_generics(GContext { g, always: false }, ty) {
1099 generics.make_where_clause().predicates.push(
1100 parse_quote_spanned! { ty.span() =>
1101 #ty: ::object_rainbow::Size
1102 },
1103 );
1104 }
1105 }
1106 generics.make_where_clause().predicates.push(parse_quote!(
1107 #size_arr: ::object_rainbow::typenum::FoldAdd<
1108 Output: ::object_rainbow::typenum::Unsigned
1109 >
1110 ));
1111 false
1112 }
1113 Data::Enum(data) => {
1114 for v in data.variants.iter() {
1115 for f in v.fields.iter() {
1116 let ty = &f.ty;
1117 if type_contains_generics(GContext { g, always: false }, ty) {
1118 generics.make_where_clause().predicates.push(
1119 parse_quote_spanned! { ty.span() =>
1120 #ty: ::object_rainbow::Size
1121 },
1122 );
1123 }
1124 }
1125 }
1126 for v in data.variants.iter().skip(1) {
1127 let arr = fields_size_arr(&v.fields, true);
1128 generics.make_where_clause().predicates.push(parse_quote!(
1129 #arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
1130 ));
1131 }
1132 generics.make_where_clause().predicates.push(parse_quote!(
1133 #size_arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
1134 ));
1135 true
1136 }
1137 Data::Union(data) => {
1138 return Err(Error::new_spanned(
1139 data.union_token,
1140 "`union`s are not supported",
1141 ));
1142 }
1143 };
1144 Ok((generics, is_enum))
1145}
1146
1147fn fields_size_arr(fields: &syn::Fields, as_enum: bool) -> proc_macro2::TokenStream {
1148 let kind_size = quote! {
1149 <
1150 <
1151 <
1152 Self
1153 as
1154 ::object_rainbow::Enum
1155 >::Kind
1156 as
1157 ::object_rainbow::enumkind::EnumKind
1158 >::Tag
1159 as ::object_rainbow::Size
1160 >::Size
1161 };
1162 if fields.is_empty() {
1163 return if as_enum {
1164 quote! { tarr![#kind_size, ::object_rainbow::typenum::consts::U0] }
1165 } else {
1166 quote! { tarr![::object_rainbow::typenum::consts::U0] }
1167 };
1168 }
1169 let size_arr = fields.iter().map(|f| {
1170 let ty = &f.ty;
1171 quote! { <#ty as ::object_rainbow::Size>::Size }
1172 });
1173 if as_enum {
1174 quote! { tarr![#kind_size, ::object_rainbow::typenum::consts::U0, #(#size_arr),*] }
1175 } else {
1176 quote! { tarr![::object_rainbow::typenum::consts::U0, #(#size_arr),*] }
1177 }
1178}
1179
1180fn gen_size_arr(data: &Data) -> proc_macro2::TokenStream {
1181 match data {
1182 Data::Struct(data) => fields_size_arr(&data.fields, false),
1183 Data::Enum(data) => {
1184 if let Some(v) = data.variants.first() {
1185 fields_size_arr(&v.fields, true)
1186 } else {
1187 Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
1188 .into_compile_error()
1189 }
1190 }
1191 Data::Union(data) => {
1192 Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1193 }
1194 }
1195}
1196
1197fn fields_size(fields: &syn::Fields) -> proc_macro2::TokenStream {
1198 if fields.is_empty() {
1199 return quote! {0};
1200 }
1201 let size = fields.iter().map(|f| {
1202 let ty = &f.ty;
1203 quote! { <#ty as ::object_rainbow::Size>::SIZE }
1204 });
1205 quote! {
1206 #(#size)+*
1207 }
1208}
1209
1210fn gen_size(data: &Data) -> proc_macro2::TokenStream {
1211 match data {
1212 Data::Struct(data) => fields_size(&data.fields),
1213 Data::Enum(data) => {
1214 if let Some(v) = data.variants.first() {
1215 let size = fields_size(&v.fields);
1216 let kind_size = quote! {
1217 <
1218 <
1219 <
1220 Self
1221 as
1222 ::object_rainbow::Enum
1223 >::Kind
1224 as
1225 ::object_rainbow::enumkind::EnumKind
1226 >::Tag
1227 as ::object_rainbow::Size
1228 >::SIZE
1229 };
1230 quote! { #kind_size + #size }
1231 } else {
1232 Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
1233 .into_compile_error()
1234 }
1235 }
1236 Data::Union(data) => {
1237 Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1238 }
1239 }
1240}
1241
1242#[proc_macro_derive(Parse, attributes(parse))]
1263pub fn derive_parse(input: TokenStream) -> TokenStream {
1264 let input = parse_macro_input!(input as DeriveInput);
1265 let name = input.ident;
1266 let generics = input.generics.clone();
1267 let (_, ty_generics, _) = generics.split_for_impl();
1268 let (inp, generics) = match bounds_parse(input.generics, &input.data, &input.attrs) {
1269 Ok(g) => g,
1270 Err(e) => return e.into_compile_error().into(),
1271 };
1272 let (parse, enum_parse) = gen_parse(&input.data, &input.attrs);
1273 let (impl_generics, _, where_clause) = generics.split_for_impl();
1274 let target = parse_for(&name, &input.attrs);
1275 let enum_parse = enum_parse.map(|enum_parse| {
1276 quote! {
1277 #[automatically_derived]
1278 impl #impl_generics ::object_rainbow::enumkind::EnumParse<#inp> for #target #ty_generics
1279 #where_clause
1280 {
1281 fn enum_parse(
1282 kind: <Self as ::object_rainbow::Enum>::Kind, mut input: #inp,
1283 ) -> ::object_rainbow::Result<Self> {
1284 #enum_parse
1285 }
1286 }
1287 }
1288 });
1289 let output = quote! {
1290 const _: () = {
1291 #[automatically_derived]
1292 impl #impl_generics ::object_rainbow::Parse<#inp> for #target #ty_generics
1293 #where_clause
1294 {
1295 fn parse(mut input: #inp) -> ::object_rainbow::Result<Self> {
1296 #parse
1297 }
1298 }
1299
1300 #enum_parse
1301 };
1302 };
1303 TokenStream::from(output)
1304}
1305
1306#[derive(Debug, FromMeta)]
1307#[darling(derive_syn_parse)]
1308struct ContainerParseArgs {
1309 #[darling(default)]
1310 unchecked: bool,
1311 #[darling(default)]
1312 bound: Option<LitStr>,
1313 #[darling(default)]
1314 generic: Option<LitStr>,
1315 #[darling(default)]
1316 input: Option<LitStr>,
1317}
1318
1319fn parse_parse_args(
1320 attrs: &[Attribute],
1321) -> syn::Result<(bool, Ident, Vec<WherePredicate>, Vec<GenericParam>)> {
1322 let mut u = false;
1323 let mut inp = parse_quote!(__I);
1324 let mut wheres = Vec::new();
1325 let mut ig = Vec::new();
1326 for attr in attrs {
1327 if attr_str(attr).as_deref() == Some("parse") {
1328 let ContainerParseArgs {
1329 unchecked,
1330 input,
1331 bound,
1332 generic,
1333 } = attr.parse_args()?;
1334 if unchecked {
1335 u = true;
1336 }
1337 if let Some(input) = input {
1338 inp = input.parse()?;
1339 }
1340 if let Some(bound) = bound {
1341 wheres.push(bound.parse()?);
1342 }
1343 if let Some(generic) = generic {
1344 ig.push(generic.parse()?);
1345 }
1346 }
1347 }
1348 Ok((u, inp, wheres, ig))
1349}
1350
1351#[derive(Debug, FromMeta)]
1352#[darling(derive_syn_parse)]
1353struct ParseArgs {
1354 #[darling(default)]
1355 unchecked: bool,
1356 with: Option<Expr>,
1357}
1358
1359fn bounds_parse(
1360 mut generics: Generics,
1361 data: &Data,
1362 attrs: &[Attribute],
1363) -> syn::Result<(Ident, Generics)> {
1364 let (recursive, _, _, _) = parse_recursive_inline(attrs)?;
1365 let (u, inp, wheres, ig) = parse_parse_args(attrs)?;
1366 let tr = |last| match (last, recursive) {
1367 (true, true) => {
1368 quote!(::object_rainbow::Parse<#inp> + ::object_rainbow::Object<#inp::Extra>)
1369 }
1370 (true, false) => quote!(::object_rainbow::Parse<#inp>),
1371 (false, true) => {
1372 quote!(::object_rainbow::ParseInline<#inp> + ::object_rainbow::Inline<#inp::Extra>)
1373 }
1374 (false, false) => quote!(::object_rainbow::ParseInline<#inp>),
1375 };
1376 match data {
1377 Data::Struct(data) => {
1378 let last_at = data.fields.len().saturating_sub(1);
1379 'field: for (i, f) in data.fields.iter().enumerate() {
1380 let last = i == last_at;
1381 let ty = &f.ty;
1382 for attr in &f.attrs {
1383 if attr_str(attr).as_deref() == Some("parse") {
1384 let ParseArgs { unchecked, .. } = attr.parse_args::<ParseArgs>()?;
1385 if unchecked {
1386 continue 'field;
1387 }
1388 }
1389 }
1390 if u {
1391 continue 'field;
1392 }
1393 let tr = tr(last);
1394 generics
1395 .make_where_clause()
1396 .predicates
1397 .push(parse_quote_spanned! { ty.span() =>
1398 #ty: #tr
1399 });
1400 }
1401 }
1402 Data::Enum(data) => {
1403 for v in data.variants.iter() {
1404 let last_at = v.fields.len().saturating_sub(1);
1405 'field: for (i, f) in v.fields.iter().enumerate() {
1406 let ty = &f.ty;
1407 for attr in &f.attrs {
1408 if attr_str(attr).as_deref() == Some("parse") {
1409 let ParseArgs { unchecked, .. } = attr.parse_args::<ParseArgs>()?;
1410 if unchecked {
1411 continue 'field;
1412 }
1413 }
1414 }
1415 if u {
1416 continue 'field;
1417 }
1418 let last = i == last_at;
1419 let tr = tr(last);
1420 generics.make_where_clause().predicates.push(
1421 parse_quote_spanned! { ty.span() =>
1422 #ty: #tr
1423 },
1424 );
1425 }
1426 }
1427 }
1428 Data::Union(data) => {
1429 return Err(Error::new_spanned(
1430 data.union_token,
1431 "`union`s are not supported",
1432 ));
1433 }
1434 }
1435 generics.params.push(if recursive {
1436 parse_quote!(#inp: ::object_rainbow::PointInput<
1437 Extra: ::core::marker::Send + ::core::marker::Sync + ::core::clone::Clone
1438 >)
1439 } else {
1440 parse_quote!(#inp: ::object_rainbow::ParseInput)
1441 });
1442 for bound in wheres {
1443 generics.make_where_clause().predicates.push(bound);
1444 }
1445 generics.params.extend(ig);
1446 Ok((inp, generics))
1447}
1448
1449fn gen_parse(
1450 data: &Data,
1451 attrs: &[Attribute],
1452) -> (proc_macro2::TokenStream, Option<proc_macro2::TokenStream>) {
1453 match parse_untagged(attrs) {
1454 Ok(None) => {}
1455 Ok(Some(untagged)) => {
1456 return (
1457 syn::Error::new(untagged.span(), "`untagged` cannot be parsed")
1458 .into_compile_error(),
1459 None,
1460 );
1461 }
1462 Err(e) => return (e.into_compile_error(), None),
1463 };
1464 match data {
1465 Data::Struct(data) => {
1466 let arm = fields_parse(&data.fields);
1467 (quote! { Ok(Self #arm)}, None)
1468 }
1469 Data::Enum(data) => {
1470 let parse = data.variants.iter().map(|v| {
1471 let ident = &v.ident;
1472 let arm = fields_parse(&v.fields);
1473 quote! {
1474 <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
1475 }
1476 });
1477 (
1478 quote! {
1479 ::object_rainbow::enumkind::EnumParse::parse_as_enum(input)
1480 },
1481 Some(if data.variants.is_empty() {
1482 quote! {
1483 match kind {}
1484 }
1485 } else {
1486 quote! {
1487 Ok(match kind {
1488 #(#parse)*
1489 })
1490 }
1491 }),
1492 )
1493 }
1494 Data::Union(data) => (
1495 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error(),
1496 None,
1497 ),
1498 }
1499}
1500
1501fn fields_parse(fields: &syn::Fields) -> proc_macro2::TokenStream {
1502 let last_at = fields.len().saturating_sub(1);
1503 match fields {
1504 syn::Fields::Named(fields) => {
1505 let parse = fields.named.iter().enumerate().map(|(i, f)| {
1506 let last = i == last_at;
1507 let mut w = None;
1508 for attr in &f.attrs {
1509 if attr_str(attr).as_deref() == Some("parse") {
1510 let ParseArgs { with, .. } = match attr.parse_args::<ParseArgs>() {
1511 Ok(args) => args,
1512 Err(e) => return e.into_compile_error(),
1513 };
1514 if let Some(with) = with {
1515 w = Some(with);
1516 }
1517 }
1518 }
1519 let i = f.ident.as_ref().unwrap();
1520 if let Some(with) = w {
1521 let arg = if last {
1522 quote!(input)
1523 } else {
1524 quote!(&mut input)
1525 };
1526 quote_spanned! { f.ty.span() =>
1527 #i: #with(#arg)?
1528 }
1529 } else {
1530 let method = if last {
1531 quote!(parse)
1532 } else {
1533 quote!(parse_inline)
1534 };
1535 quote_spanned! { f.ty.span() =>
1536 #i: input.#method()?
1537 }
1538 }
1539 });
1540 quote! { { #(#parse),* } }
1541 }
1542 syn::Fields::Unnamed(fields) => {
1543 let parse = fields.unnamed.iter().enumerate().map(|(i, f)| {
1544 let mut w = None;
1545 for attr in &f.attrs {
1546 if attr_str(attr).as_deref() == Some("parse") {
1547 let ParseArgs { with, .. } = match attr.parse_args::<ParseArgs>() {
1548 Ok(args) => args,
1549 Err(e) => return e.into_compile_error(),
1550 };
1551 if let Some(with) = with {
1552 w = Some(with);
1553 }
1554 }
1555 }
1556 let last = i == last_at;
1557 if let Some(with) = w {
1558 let arg = if last {
1559 quote!(input)
1560 } else {
1561 quote!(&mut input)
1562 };
1563 quote_spanned! { f.ty.span() =>
1564 #with(#arg)?
1565 }
1566 } else {
1567 let method = if last {
1568 quote!(parse)
1569 } else {
1570 quote!(parse_inline)
1571 };
1572 quote_spanned! { f.ty.span() =>
1573 input.#method()?
1574 }
1575 }
1576 });
1577 quote! { (#(#parse),*) }
1578 }
1579 syn::Fields::Unit => quote! {},
1580 }
1581}
1582
1583#[proc_macro_derive(ParseInline, attributes(parse))]
1604pub fn derive_parse_inline(input: TokenStream) -> TokenStream {
1605 let input = parse_macro_input!(input as DeriveInput);
1606 let name = input.ident;
1607 let generics = input.generics.clone();
1608 let (_, ty_generics, _) = generics.split_for_impl();
1609 let (inp, generics) = match bounds_parse_inline(input.generics, &input.data, &input.attrs) {
1610 Ok(g) => g,
1611 Err(e) => return e.into_compile_error().into(),
1612 };
1613 let (parse_inline, enum_parse_inline) = gen_parse_inline(&input.data);
1614 let (impl_generics, _, where_clause) = generics.split_for_impl();
1615 let target = parse_for(&name, &input.attrs);
1616 let enum_parse_inline = enum_parse_inline.map(|enum_parse_inline| {
1617 quote! {
1618 #[automatically_derived]
1619 impl #impl_generics ::object_rainbow::enumkind::EnumParseInline<#inp>
1620 for #target #ty_generics #where_clause {
1621 fn enum_parse_inline(
1622 kind: <Self as ::object_rainbow::Enum>::Kind, input: &mut #inp,
1623 ) -> ::object_rainbow::Result<Self> {
1624 #enum_parse_inline
1625 }
1626 }
1627 }
1628 });
1629 let output = quote! {
1630 #[automatically_derived]
1631 impl #impl_generics ::object_rainbow::ParseInline<#inp>
1632 for #target #ty_generics #where_clause {
1633 fn parse_inline(input: &mut #inp) -> ::object_rainbow::Result<Self> {
1634 #parse_inline
1635 }
1636 }
1637
1638 #enum_parse_inline
1639 };
1640 TokenStream::from(output)
1641}
1642
1643fn bounds_parse_inline(
1644 mut generics: Generics,
1645 data: &Data,
1646 attrs: &[Attribute],
1647) -> syn::Result<(Ident, Generics)> {
1648 let (recursive, _, _, _) = parse_recursive_inline(attrs)?;
1649 let (u, inp, wheres, ig) = parse_parse_args(attrs)?;
1650 let tr = if recursive {
1651 quote!(::object_rainbow::ParseInline<#inp> + ::object_rainbow::Inline<#inp::Extra>)
1652 } else {
1653 quote!(::object_rainbow::ParseInline<#inp>)
1654 };
1655 match data {
1656 Data::Struct(data) => {
1657 'field: for f in data.fields.iter() {
1658 let ty = &f.ty;
1659 for attr in &f.attrs {
1660 if attr_str(attr).as_deref() == Some("parse") {
1661 let ParseArgs { unchecked, .. } = attr.parse_args::<ParseArgs>()?;
1662 if unchecked {
1663 continue 'field;
1664 }
1665 }
1666 }
1667 if u {
1668 continue 'field;
1669 }
1670 generics
1671 .make_where_clause()
1672 .predicates
1673 .push(parse_quote_spanned! { ty.span() =>
1674 #ty: #tr
1675 });
1676 }
1677 }
1678 Data::Enum(data) => {
1679 for v in data.variants.iter() {
1680 'field: for f in v.fields.iter() {
1681 let ty = &f.ty;
1682 for attr in &f.attrs {
1683 if attr_str(attr).as_deref() == Some("parse") {
1684 let ParseArgs { unchecked, .. } = attr.parse_args::<ParseArgs>()?;
1685 if unchecked {
1686 continue 'field;
1687 }
1688 }
1689 }
1690 if u {
1691 continue 'field;
1692 }
1693 generics.make_where_clause().predicates.push(
1694 parse_quote_spanned! { ty.span() =>
1695 #ty: #tr
1696 },
1697 );
1698 }
1699 }
1700 }
1701 Data::Union(data) => {
1702 return Err(Error::new_spanned(
1703 data.union_token,
1704 "`union`s are not supported",
1705 ));
1706 }
1707 }
1708 generics.params.push(if recursive {
1709 parse_quote!(#inp: ::object_rainbow::PointInput<
1710 Extra: ::core::marker::Send + ::core::marker::Sync
1711 >)
1712 } else {
1713 parse_quote!(#inp: ::object_rainbow::ParseInput)
1714 });
1715 for bound in wheres {
1716 generics.make_where_clause().predicates.push(bound);
1717 }
1718 for generic in ig {
1719 generics.params.push(parse_quote!(#generic));
1720 }
1721 Ok((inp, generics))
1722}
1723
1724fn fields_parse_inline(fields: &syn::Fields) -> proc_macro2::TokenStream {
1725 match fields {
1726 syn::Fields::Named(fields) => {
1727 let parse = fields.named.iter().map(|f| {
1728 let i = f.ident.as_ref().unwrap();
1729 quote_spanned! { f.ty.span() =>
1730 #i: input.parse_inline()?
1731 }
1732 });
1733 quote! { { #(#parse),* } }
1734 }
1735 syn::Fields::Unnamed(fields) => {
1736 let parse = fields.unnamed.iter().map(|f| {
1737 quote_spanned! { f.ty.span() =>
1738 input.parse_inline()?
1739 }
1740 });
1741 quote! { (#(#parse),*) }
1742 }
1743 syn::Fields::Unit => quote! {},
1744 }
1745}
1746
1747fn gen_parse_inline(data: &Data) -> (proc_macro2::TokenStream, Option<proc_macro2::TokenStream>) {
1748 match data {
1749 Data::Struct(data) => {
1750 let arm = fields_parse_inline(&data.fields);
1751 (quote! { Ok(Self #arm) }, None)
1752 }
1753 Data::Enum(data) => {
1754 let parse_inline = data.variants.iter().map(|v| {
1755 let ident = &v.ident;
1756 let arm = fields_parse_inline(&v.fields);
1757 quote! {
1758 <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
1759 }
1760 });
1761 (
1762 quote! {
1763 ::object_rainbow::enumkind::EnumParseInline::parse_as_inline_enum(input)
1764 },
1765 Some(if data.variants.is_empty() {
1766 quote! {
1767 match kind {}
1768 }
1769 } else {
1770 quote! {
1771 Ok(match kind {
1772 #(#parse_inline)*
1773 })
1774 }
1775 }),
1776 )
1777 }
1778 Data::Union(data) => (
1779 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error(),
1780 None,
1781 ),
1782 }
1783}
1784
1785#[proc_macro_derive(ParseAsInline)]
1802pub fn derive_parse_as_inline(input: TokenStream) -> TokenStream {
1803 let input = parse_macro_input!(input as DeriveInput);
1804 let name = input.ident;
1805 let generics = input.generics.clone();
1806 let (_, ty_generics, _) = generics.split_for_impl();
1807 let generics = match bounds_parse_as_inline(input.generics, &name) {
1808 Ok(g) => g,
1809 Err(e) => return e.into_compile_error().into(),
1810 };
1811 let (impl_generics, _, where_clause) = generics.split_for_impl();
1812 let target = parse_for(&name, &input.attrs);
1813 let output = quote! {
1814 #[automatically_derived]
1815 impl #impl_generics ::object_rainbow::Parse<__I> for #target #ty_generics #where_clause {
1816 fn parse(input: __I) -> ::object_rainbow::Result<Self> {
1817 ::object_rainbow::ParseInline::<__I>::parse_as_inline(input)
1818 }
1819 }
1820 };
1821 TokenStream::from(output)
1822}
1823
1824fn bounds_parse_as_inline(mut generics: Generics, name: &Ident) -> syn::Result<Generics> {
1825 generics
1826 .make_where_clause()
1827 .predicates
1828 .push(parse_quote_spanned! { name.span() =>
1829 Self: ::object_rainbow::ParseInline::<__I>
1830 });
1831 generics
1832 .params
1833 .push(parse_quote!(__I: ::object_rainbow::ParseInput));
1834 Ok(generics)
1835}
1836
1837fn parse_path(attr: &Attribute) -> syn::Result<Type> {
1838 attr.parse_args::<LitStr>()?.parse()
1839}
1840
1841fn attr_str(attr: &Attribute) -> Option<String> {
1842 Some(attr.path().get_ident()?.to_string())
1843}
1844
1845#[proc_macro_derive(Enum, attributes(enumtag))]
1929pub fn derive_enum(input: TokenStream) -> TokenStream {
1930 let input = parse_macro_input!(input as DeriveInput);
1931 let name = input.ident;
1932 let generics = input.generics.clone();
1933 let (_, ty_generics, _) = generics.split_for_impl();
1934 let generics = input.generics;
1935 let length = gen_length(&input.data);
1936 let variants = gen_variants(&input.data);
1937 let variant_count = gen_variant_count(&input.data);
1938 let to_tag = gen_to_tag(&input.data);
1939 let from_tag = gen_from_tag(&input.data);
1940 let kind = gen_kind(&input.data);
1941 let (impl_generics, _, where_clause) = generics.split_for_impl();
1942 let mut errors = Vec::new();
1943 let mut enumtag = None;
1944 for attr in &input.attrs {
1945 if attr_str(attr).as_deref() == Some("enumtag") {
1946 match parse_path(attr) {
1947 Ok(path) => {
1948 if enumtag.is_some() {
1949 errors.push(Error::new_spanned(path, "duplicate tag"));
1950 } else {
1951 enumtag = Some(path);
1952 }
1953 }
1954 Err(e) => errors.push(e),
1955 }
1956 }
1957 }
1958 let enumtag = enumtag.unwrap_or_else(|| {
1959 parse_quote!(
1960 ::object_rainbow::partial_byte_tag::PartialByteTag<#length>
1961 )
1962 });
1963 let errors = errors.into_iter().map(|e| e.into_compile_error());
1964 let target = parse_for(&name, &input.attrs);
1965 let output = quote! {
1966 const _: () = {
1967 #(#errors)*
1968
1969 use ::object_rainbow::enumkind::EnumKind;
1970
1971 #[derive(Clone, Copy, ::object_rainbow::ParseAsInline)]
1972 pub enum __Kind {
1973 #variants
1974 }
1975
1976 #[automatically_derived]
1977 impl ::object_rainbow::enumkind::EnumKind for __Kind {
1978 type Tag = ::object_rainbow::enumkind::EnumTag<
1979 #enumtag,
1980 #variant_count,
1981 >;
1982
1983 fn to_tag(self) -> Self::Tag {
1984 #to_tag
1985 }
1986
1987 fn from_tag(tag: Self::Tag) -> Self {
1988 #from_tag
1989 }
1990 }
1991
1992 impl<I: ::object_rainbow::ParseInput> ::object_rainbow::ParseInline<I> for __Kind {
1993 fn parse_inline(input: &mut I) -> ::object_rainbow::Result<Self> {
1994 Ok(::object_rainbow::enumkind::EnumKind::from_tag(input.parse_inline()?))
1995 }
1996 }
1997
1998 impl ::object_rainbow::MaybeHasNiche for __Kind {
1999 type MnArray = <#enumtag as ::object_rainbow::MaybeHasNiche>::MnArray;
2000 }
2001
2002 #[automatically_derived]
2003 impl #impl_generics ::object_rainbow::Enum for #target #ty_generics #where_clause {
2004 type Kind = __Kind;
2005
2006 fn kind(&self) -> Self::Kind {
2007 #kind
2008 }
2009 }
2010 };
2011 };
2012 TokenStream::from(output)
2013}
2014
2015fn gen_length(data: &Data) -> proc_macro2::TokenStream {
2016 match data {
2017 Data::Struct(data) => {
2018 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2019 }
2020 Data::Enum(data) => {
2021 let name = format!("U{}", data.variants.len());
2022 let ident = Ident::new(&name, data.variants.span());
2023 quote! { ::object_rainbow::typenum::#ident }
2024 }
2025 Data::Union(data) => {
2026 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2027 }
2028 }
2029}
2030
2031fn gen_variants(data: &Data) -> proc_macro2::TokenStream {
2032 match data {
2033 Data::Struct(data) => {
2034 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2035 }
2036 Data::Enum(data) => {
2037 let variants = data.variants.iter().map(|v| &v.ident);
2038 quote! { #(#variants),* }
2039 }
2040 Data::Union(data) => {
2041 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2042 }
2043 }
2044}
2045
2046fn gen_variant_count(data: &Data) -> proc_macro2::TokenStream {
2047 match data {
2048 Data::Struct(data) => {
2049 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2050 }
2051 Data::Enum(data) => {
2052 let variant_count = data.variants.len();
2053 quote! { #variant_count }
2054 }
2055 Data::Union(data) => {
2056 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2057 }
2058 }
2059}
2060
2061fn gen_to_tag(data: &Data) -> proc_macro2::TokenStream {
2062 match data {
2063 Data::Struct(data) => {
2064 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2065 }
2066 Data::Enum(data) => {
2067 let to_tag = data.variants.iter().enumerate().map(|(i, v)| {
2068 let ident = &v.ident;
2069 quote_spanned! { ident.span() =>
2070 Self::#ident => ::object_rainbow::enumkind::EnumTag::from_const::<#i>(),
2071 }
2072 });
2073 quote! {
2074 match self {
2075 #(#to_tag)*
2076 }
2077 }
2078 }
2079 Data::Union(data) => {
2080 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2081 }
2082 }
2083}
2084
2085fn gen_from_tag(data: &Data) -> proc_macro2::TokenStream {
2086 match data {
2087 Data::Struct(data) => {
2088 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2089 }
2090 Data::Enum(data) => {
2091 let from_tag = data.variants.iter().enumerate().map(|(i, v)| {
2092 let ident = &v.ident;
2093 quote_spanned! { ident.span() =>
2094 #i => Self::#ident,
2095 }
2096 });
2097 quote! {
2098 match tag.to_usize() {
2099 #(#from_tag)*
2100 _ => unreachable!(),
2101 }
2102 }
2103 }
2104 Data::Union(data) => {
2105 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2106 }
2107 }
2108}
2109
2110fn gen_kind(data: &Data) -> proc_macro2::TokenStream {
2111 match data {
2112 Data::Struct(data) => {
2113 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2114 }
2115 Data::Enum(data) => {
2116 if data.variants.is_empty() {
2117 return quote! {
2118 match *self {}
2119 };
2120 }
2121 let variants = data.variants.iter().map(|v| {
2122 let ident = &v.ident;
2123 quote_spanned! { ident.span() =>
2124 Self::#ident {..} => __Kind::#ident,
2125 }
2126 });
2127 quote! {
2128 match self {
2129 #(#variants)*
2130 }
2131 }
2132 }
2133 Data::Union(data) => {
2134 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2135 }
2136 }
2137}
2138
2139#[proc_macro_derive(MaybeHasNiche, attributes(niche))]
2152pub fn derive_maybe_has_niche(input: TokenStream) -> TokenStream {
2153 let input = parse_macro_input!(input as DeriveInput);
2154 let name = input.ident;
2155 let mn_array = gen_mn_array(&input.data, &input.attrs);
2156 let (_, ty_generics, _) = input.generics.split_for_impl();
2157 let generics = match bounds_maybe_has_niche(input.generics.clone(), &input.data, &input.attrs) {
2158 Ok(g) => g,
2159 Err(e) => return e.into_compile_error().into(),
2160 };
2161 let (impl_generics, _, where_clause) = generics.split_for_impl();
2162 let target = parse_for(&name, &input.attrs);
2163 let output = quote! {
2164 const _: () = {
2165 use ::object_rainbow::typenum::tarr;
2166
2167 #[automatically_derived]
2168 impl #impl_generics ::object_rainbow::MaybeHasNiche
2169 for #target #ty_generics #where_clause {
2170 type MnArray = #mn_array;
2171 }
2172 };
2173 };
2174 TokenStream::from(output)
2175}
2176
2177#[derive(Debug, FromMeta)]
2178#[darling(derive_syn_parse)]
2179struct ContainerNicheArgs {
2180 #[darling(default)]
2181 tag: bool,
2182}
2183
2184fn parse_niche_tag(attrs: &[Attribute]) -> syn::Result<bool> {
2185 let mut t = false;
2186 for attr in attrs {
2187 if attr_str(attr).as_deref() == Some("niche") {
2188 let ContainerNicheArgs { tag } = attr.parse_args()?;
2189 if tag {
2190 t = true;
2191 }
2192 }
2193 }
2194 Ok(t)
2195}
2196
2197fn bounds_maybe_has_niche(
2198 mut generics: Generics,
2199 data: &Data,
2200 attrs: &[Attribute],
2201) -> syn::Result<Generics> {
2202 let tag = parse_niche_tag(attrs)?;
2203 match data {
2204 Data::Struct(data) => {
2205 for f in data.fields.iter() {
2206 let ty = &f.ty;
2207 generics
2208 .make_where_clause()
2209 .predicates
2210 .push(parse_quote_spanned! { ty.span() =>
2211 #ty: ::object_rainbow::MaybeHasNiche<
2212 MnArray: ::object_rainbow::MnArray<
2213 MaybeNiche: ::object_rainbow::MaybeNiche
2214 >
2215 >
2216 });
2217 }
2218 }
2219 Data::Enum(data) => {
2220 if tag {
2221 return Ok(generics);
2222 }
2223 generics.params.push(parse_quote!(
2224 __N: ::object_rainbow::typenum::Unsigned
2225 ));
2226 for (i, v) in data.variants.iter().enumerate() {
2227 let mn_array = fields_mn_array(&v.fields, Some(i));
2228 generics
2229 .make_where_clause()
2230 .predicates
2231 .push(parse_quote_spanned! { v.span() =>
2232 #mn_array: ::object_rainbow::MnArray<
2233 MaybeNiche: ::object_rainbow::NicheOr<N = __N>
2234 >
2235 });
2236 for f in v.fields.iter() {
2237 let ty = &f.ty;
2238 generics.make_where_clause().predicates.push(
2239 parse_quote_spanned! { ty.span() =>
2240 #ty: ::object_rainbow::MaybeHasNiche<
2241 MnArray: ::object_rainbow::MnArray<
2242 MaybeNiche: ::object_rainbow::MaybeNiche
2243 >
2244 >
2245 },
2246 );
2247 }
2248 }
2249 }
2250 Data::Union(data) => {
2251 return Err(Error::new_spanned(
2252 data.union_token,
2253 "`union`s are not supported",
2254 ));
2255 }
2256 }
2257 Ok(generics)
2258}
2259
2260fn fields_mn_array(fields: &syn::Fields, variant: Option<usize>) -> proc_macro2::TokenStream {
2261 let mn_array = fields.iter().map(|f| {
2262 let ty = &f.ty;
2263 quote! {
2264 <
2265 <
2266 #ty
2267 as
2268 ::object_rainbow::MaybeHasNiche
2269 >::MnArray
2270 as
2271 ::object_rainbow::MnArray
2272 >::MaybeNiche
2273 }
2274 });
2275 if let Some(variant) = variant {
2276 let kind_niche = quote! {
2277 ::object_rainbow::AutoEnumNiche<Self, #variant>
2278 };
2279 quote! {
2280 tarr![
2281 #kind_niche,
2282 ::object_rainbow::NoNiche<::object_rainbow::HackNiche<#variant>>, #(#mn_array),*
2283 ]
2284 }
2285 } else {
2286 quote! { tarr![#(#mn_array),*] }
2287 }
2288}
2289
2290fn gen_mn_array(data: &Data, attrs: &[Attribute]) -> proc_macro2::TokenStream {
2291 let tag = match parse_niche_tag(attrs) {
2292 Ok(tag) => tag,
2293 Err(e) => return e.into_compile_error(),
2294 };
2295 match data {
2296 Data::Struct(data) => fields_mn_array(&data.fields, None),
2297 Data::Enum(data) => {
2298 if tag {
2299 return quote! {
2300 <
2301 <Self as ::object_rainbow::Enum>::Kind as ::object_rainbow::MaybeHasNiche
2302 >::MnArray
2303 };
2304 }
2305 let mn_array = data.variants.iter().enumerate().map(|(i, v)| {
2306 let mn_array = fields_mn_array(&v.fields, Some(i));
2307 quote! { <#mn_array as ::object_rainbow::MnArray>::MaybeNiche }
2308 });
2309 quote! {
2310 ::object_rainbow::NicheFoldOrArray<tarr![#(#mn_array),*]>
2311 }
2312 }
2313 Data::Union(data) => {
2314 Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
2315 }
2316 }
2317}
2318
2319#[proc_macro_attribute]
2320pub fn derive_for_wrapped(args: TokenStream, input: TokenStream) -> TokenStream {
2321 let input = parse_macro_input!(input as ItemTrait);
2322 let sup = if args.is_empty() {
2323 let sup = input.supertraits.clone();
2324 quote!(#sup)
2325 } else {
2326 args.into()
2327 };
2328 let name = input.ident.clone();
2329 let generics = input.generics.clone();
2330 let (_, ty_generics, _) = generics.split_for_impl();
2331 let mut derived = Vec::new();
2332 for (path, extra) in [
2333 (
2334 quote!(map_extra::MappedExtra),
2335 vec![(quote!(__M), quote!(#sup))],
2336 ),
2337 (quote!(length_prefixed::Lp), vec![]),
2338 ] {
2339 let mut generics = input.generics.clone();
2340 generics.params.push(parse_quote! {
2341 __T: #name #ty_generics
2342 });
2343 for (i, ty) in &extra {
2344 generics.params.push(parse_quote! {
2345 #i: #ty
2346 });
2347 }
2348 let (impl_generics, _, where_clause) = generics.split_for_impl();
2349 let i = input
2350 .items
2351 .clone()
2352 .into_iter()
2353 .map(|i| match i {
2354 TraitItem::Const(i) => ImplItem::Const({
2355 let const_token = i.const_token;
2356 let ident = i.ident;
2357 let colon_token = i.colon_token;
2358 let ty = i.ty;
2359 let semi_token = i.semi_token;
2360 parse_quote! {
2361 #const_token
2362 #ident
2363 #colon_token
2364 #ty
2365 =
2366 <__T as #name #ty_generics>::#ident
2367 #semi_token
2368 }
2369 }),
2370 TraitItem::Fn(i) => ImplItem::Fn({
2371 let mut sig = i.sig;
2372 let ident = sig.ident.clone();
2373 let args = sig
2374 .inputs
2375 .iter_mut()
2376 .enumerate()
2377 .map(|(n, i)| match i {
2378 FnArg::Receiver(receiver) => {
2379 let reference = receiver.reference.as_ref().map(|(and, _)| and);
2380 let mutability = receiver.mutability.as_ref();
2381 let ident = &receiver.self_token;
2382 quote!(#reference #mutability *#ident)
2383 }
2384 FnArg::Typed(pat_type) => {
2385 let ident = Ident::new(&format!("arg{n}"), pat_type.span());
2386 *pat_type.pat = parse_quote!(#ident);
2387 quote!(#ident)
2388 }
2389 })
2390 .collect::<Vec<_>>();
2391 parse_quote! {
2392 #sig
2393 {
2394 <__T as #name #ty_generics>::#ident(
2395 #(#args),*
2396 )
2397 }
2398 }
2399 }),
2400 TraitItem::Type(i) => ImplItem::Type({
2401 let type_token = i.type_token;
2402 let ident = i.ident;
2403 let semi_token = i.semi_token;
2404 parse_quote! {
2405 #type_token
2406 #ident
2407 =
2408 <__T as #name #ty_generics>::#ident
2409 #semi_token
2410 }
2411 }),
2412 _ => unimplemented!("unknown/unsupported item"),
2413 })
2414 .collect::<Vec<_>>();
2415 let extra = extra.into_iter().map(|(k, _)| k);
2416 derived.push(quote! {
2417 impl #impl_generics #name #ty_generics for ::object_rainbow::#path<
2418 __T,
2419 #(#extra),*
2420 >
2421 #where_clause
2422 {
2423 #(#i)*
2424 }
2425 });
2426 }
2427 let output = quote! {
2428 #input
2429
2430 #(#derived)*
2431 };
2432 output.into()
2433}