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