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