1use std::collections::BTreeSet;
4
5use darling::{FromMeta, util::SpannedValue};
6use proc_macro::TokenStream;
7use proc_macro2::Span;
8use quote::{ToTokens, quote, quote_spanned};
9use syn::{
10 Attribute, Data, DeriveInput, Error, Expr, FnArg, GenericParam, Generics, Ident, ImplItem,
11 Item, ItemTrait, LitStr, TraitItem, Type, WherePredicate, parse::Parse, parse_macro_input,
12 parse_quote, parse_quote_spanned, spanned::Spanned, token::Comma,
13};
14
15use self::contains_generics::{GContext, type_contains_generics};
16
17mod contains_generics;
18
19fn bounds_g(generics: &Generics) -> BTreeSet<Ident> {
21 generics
22 .params
23 .iter()
24 .filter_map(|param| match param {
25 GenericParam::Lifetime(_) => None,
26 GenericParam::Type(param) => Some(¶m.ident),
27 GenericParam::Const(param) => Some(¶m.ident),
28 })
29 .cloned()
30 .collect()
31}
32
33#[derive(Debug, FromMeta)]
34#[darling(derive_syn_parse)]
35struct RainbowArgs {
36 #[darling(default)]
37 remote: Option<Type>,
38 #[darling(default)]
39 untagged: SpannedValue<bool>,
40}
41
42fn parse_for(name: &Ident, attrs: &[Attribute]) -> proc_macro2::TokenStream {
43 for attr in attrs {
44 if attr_str(attr).as_deref() == Some("rainbow") {
45 match attr.parse_args::<RainbowArgs>() {
46 Ok(RainbowArgs { remote, .. }) => {
47 if let Some(remote) = remote {
48 return remote.to_token_stream();
49 }
50 }
51 Err(e) => return e.into_compile_error(),
52 }
53 }
54 }
55 name.to_token_stream()
56}
57
58fn parse_untagged(attrs: &[Attribute]) -> syn::Result<Option<SpannedValue<bool>>> {
59 let mut u = None;
60 for attr in attrs {
61 if attr_str(attr).as_deref() == Some("rainbow") {
62 let RainbowArgs { untagged, .. } = attr.parse_args()?;
63 if *untagged {
64 u = Some(untagged);
65 }
66 }
67 }
68 Ok(u)
69}
70
71#[proc_macro_derive(ToOutput, attributes(rainbow, output))]
91pub fn derive_to_output(input: TokenStream) -> TokenStream {
92 let input = parse_macro_input!(input as DeriveInput);
93 let name = input.ident;
94 let generics = match bounds_to_output(input.generics, &input.data, &input.attrs) {
95 Ok(g) => g,
96 Err(e) => return e.into_compile_error().into(),
97 };
98 let to_output = gen_to_output(&input.data, &input.attrs);
99 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
100 let target = parse_for(&name, &input.attrs);
101 let output = quote! {
102 #[automatically_derived]
103 impl #impl_generics ::object_rainbow::ToOutput for #target #ty_generics #where_clause {
104 fn to_output(&self, output: &mut (impl ?::core::marker::Sized + ::object_rainbow::Output)) {
105 #to_output
106 }
107 }
108 };
109 TokenStream::from(output)
110}
111
112#[derive(Debug, FromMeta)]
113#[darling(derive_syn_parse)]
114struct ContainerOutputArgs {
115 #[darling(default)]
116 unchecked: bool,
117 #[darling(default)]
118 bound: Option<LitStr>,
119 #[darling(default)]
120 auto: Option<Type>,
121}
122
123#[derive(Debug, FromMeta)]
124#[darling(derive_syn_parse)]
125struct FieldOutputArgs {
126 #[darling(default)]
127 unchecked: bool,
128}
129
130fn parse_output_bounds(attrs: &[Attribute]) -> syn::Result<(bool, Vec<WherePredicate>, Vec<Type>)> {
131 let mut u = false;
132 let mut wheres = Vec::new();
133 let mut a = Vec::new();
134 for attr in attrs {
135 if attr_str(attr).as_deref() == Some("output") {
136 let ContainerOutputArgs {
137 unchecked,
138 bound,
139 auto,
140 } = attr.parse_args()?;
141 if unchecked {
142 u = true;
143 }
144 if let Some(bound) = bound {
145 wheres.push(bound.parse()?);
146 }
147 a.extend(auto);
148 }
149 }
150 Ok((u, wheres, a))
151}
152
153fn bounds_to_output(
154 mut generics: Generics,
155 data: &Data,
156 attrs: &[Attribute],
157) -> syn::Result<Generics> {
158 let (u, wheres, auto) = parse_output_bounds(attrs)?;
159 let g = &bounds_g(&generics);
160 match data {
161 Data::Struct(data) => {
162 let last_at = data.fields.len().saturating_sub(1);
163 'field: for (i, f) in data.fields.iter().enumerate() {
164 let last = i == last_at;
165 let ty = &f.ty;
166 let tr = if last {
167 quote!(::object_rainbow::ToOutput)
168 } else {
169 quote!(::object_rainbow::InlineOutput)
170 };
171 for attr in &f.attrs {
172 if attr_str(attr).as_deref() == Some("output") {
173 let FieldOutputArgs { unchecked, .. } = attr.parse_args()?;
174 if unchecked {
175 continue 'field;
176 }
177 }
178 }
179 if u {
180 continue 'field;
181 }
182 if !last || type_contains_generics(GContext { g, always: false }, ty) {
183 generics.make_where_clause().predicates.push(
184 parse_quote_spanned! { ty.span() =>
185 #ty: #tr
186 },
187 );
188 }
189 }
190 }
191 Data::Enum(data) => {
192 for v in data.variants.iter() {
193 let last_at = v.fields.len().saturating_sub(1);
194 'field: for (i, f) in v.fields.iter().enumerate() {
195 let last = i == last_at;
196 let ty = &f.ty;
197 let tr = if last {
198 quote!(::object_rainbow::ToOutput)
199 } else {
200 quote!(::object_rainbow::InlineOutput)
201 };
202 for attr in &f.attrs {
203 if attr_str(attr).as_deref() == Some("output") {
204 let FieldOutputArgs { unchecked, .. } = attr.parse_args()?;
205 if unchecked {
206 continue 'field;
207 }
208 }
209 }
210 if u {
211 continue 'field;
212 }
213 if !last || type_contains_generics(GContext { g, always: false }, ty) {
214 generics.make_where_clause().predicates.push(
215 parse_quote_spanned! { ty.span() =>
216 #ty: #tr
217 },
218 );
219 }
220 }
221 }
222 }
223 Data::Union(data) => {
224 return Err(Error::new_spanned(
225 data.union_token,
226 "`union`s are not supported",
227 ));
228 }
229 }
230 for bound in wheres {
231 generics.make_where_clause().predicates.push(bound);
232 }
233 for auto in auto {
234 generics
235 .make_where_clause()
236 .predicates
237 .push(parse_quote_spanned! { auto.span() =>
238 #auto: ::object_rainbow::ToOutput
239 });
240 }
241 Ok(generics)
242}
243
244fn fields_to_output(fields: &syn::Fields) -> proc_macro2::TokenStream {
245 match fields {
246 syn::Fields::Named(fields) => {
247 let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
248 let to_output = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
249 quote_spanned! { f.ty.span() =>
250 #i.to_output(output)
251 }
252 });
253 quote! {
254 { #(#let_self),* } => {
255 #(#to_output);*
256 }
257 }
258 }
259 syn::Fields::Unnamed(fields) => {
260 let let_self = fields
261 .unnamed
262 .iter()
263 .enumerate()
264 .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
265 let to_output = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
266 quote_spanned! { f.ty.span() =>
267 #i.to_output(output)
268 }
269 });
270 quote! {
271 (#(#let_self),*) => {
272 #(#to_output);*
273 }
274 }
275 }
276 syn::Fields::Unit => quote! {
277 => {}
278 },
279 }
280}
281
282fn gen_to_output(data: &Data, attrs: &[Attribute]) -> proc_macro2::TokenStream {
283 let untagged = match parse_untagged(attrs) {
284 Ok(untagged) => untagged,
285 Err(e) => return e.into_compile_error(),
286 };
287 match data {
288 Data::Struct(data) => {
289 let arm = fields_to_output(&data.fields);
290 quote! {
291 match self {
292 Self #arm
293 }
294 }
295 }
296 Data::Enum(data) => {
297 if data.variants.is_empty() {
298 return quote! {};
299 }
300 let to_output = data.variants.iter().map(|v| {
301 let ident = &v.ident;
302 let arm = fields_to_output(&v.fields);
303 quote! { Self::#ident #arm }
304 });
305 let tagged = if untagged.is_none() {
306 quote! {
307 let kind = ::object_rainbow::Enum::kind(self);
308 let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
309 tag.to_output(output);
310 }
311 } else {
312 quote! {}
313 };
314 quote! {
315 #tagged
316 match self {
317 #(#to_output)*
318 }
319 }
320 }
321 Data::Union(data) => {
322 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
323 }
324 }
325}
326
327#[proc_macro_derive(InlineOutput)]
347pub fn derive_inline_output(input: TokenStream) -> TokenStream {
348 let input = parse_macro_input!(input as DeriveInput);
349 let name = input.ident;
350 let generics = match bounds_inline_output(input.generics, &input.data, &input.attrs) {
351 Ok(g) => g,
352 Err(e) => return e.into_compile_error().into(),
353 };
354 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
355 let target = parse_for(&name, &input.attrs);
356 let output = quote! {
357 #[automatically_derived]
358 impl #impl_generics ::object_rainbow::InlineOutput for #target #ty_generics #where_clause {}
359 };
360 TokenStream::from(output)
361}
362
363fn bounds_inline_output(
364 mut generics: Generics,
365 data: &Data,
366 attrs: &[Attribute],
367) -> syn::Result<Generics> {
368 let (u, wheres, auto) = parse_output_bounds(attrs)?;
369 match data {
370 Data::Struct(data) => {
371 'field: for f in data.fields.iter() {
372 let ty = &f.ty;
373 for attr in &f.attrs {
374 if attr_str(attr).as_deref() == Some("output") {
375 let FieldOutputArgs { unchecked, .. } = attr.parse_args()?;
376 if unchecked {
377 continue 'field;
378 }
379 }
380 }
381 if u {
382 continue 'field;
383 }
384 generics
385 .make_where_clause()
386 .predicates
387 .push(parse_quote_spanned! { ty.span() =>
388 #ty: ::object_rainbow::InlineOutput
389 });
390 }
391 }
392 Data::Enum(data) => {
393 for v in data.variants.iter() {
394 'field: for f in v.fields.iter() {
395 let ty = &f.ty;
396 for attr in &f.attrs {
397 if attr_str(attr).as_deref() == Some("output") {
398 let FieldOutputArgs { unchecked, .. } = attr.parse_args()?;
399 if unchecked {
400 continue 'field;
401 }
402 }
403 }
404 if u {
405 continue 'field;
406 }
407 generics.make_where_clause().predicates.push(
408 parse_quote_spanned! { ty.span() =>
409 #ty: ::object_rainbow::InlineOutput
410 },
411 );
412 }
413 }
414 }
415 Data::Union(data) => {
416 return Err(Error::new_spanned(
417 data.union_token,
418 "`union`s are not supported",
419 ));
420 }
421 }
422 for bound in wheres {
423 generics.make_where_clause().predicates.push(bound);
424 }
425 for auto in auto {
426 generics
427 .make_where_clause()
428 .predicates
429 .push(parse_quote_spanned! { auto.span() =>
430 #auto: ::object_rainbow::InlineOutput
431 });
432 }
433 Ok(generics)
434}
435
436#[proc_macro_derive(ByteOrd)]
437pub fn derive_byte_ord(input: TokenStream) -> TokenStream {
438 let input = parse_macro_input!(input as DeriveInput);
439 let name = input.ident;
440 let generics = match bounds_byte_ord(input.generics, &input.data) {
441 Ok(g) => g,
442 Err(e) => return e.into_compile_error().into(),
443 };
444 let bytes_cmp = gen_bytes_cmp(&input.data);
445 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
446 let target = parse_for(&name, &input.attrs);
447 let output = quote! {
448 #[automatically_derived]
449 impl #impl_generics ::object_rainbow::ByteOrd for #target #ty_generics #where_clause {
450 #[allow(nonstandard_style)]
451 fn bytes_cmp(&self, other: &Self) -> ::core::cmp::Ordering {
452 #bytes_cmp
453 }
454 }
455 };
456 TokenStream::from(output)
457}
458
459fn bounds_byte_ord(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
460 let g = &bounds_g(&generics);
461 match data {
462 Data::Struct(data) => {
463 'field: for f in data.fields.iter() {
464 let ty = &f.ty;
465 let tr = quote!(::object_rainbow::ByteOrd);
466 for attr in &f.attrs {
467 if attr_str(attr).as_deref() == Some("output") {
468 let FieldOutputArgs { unchecked, .. } = attr.parse_args()?;
469 if unchecked {
470 continue 'field;
471 }
472 }
473 }
474 if type_contains_generics(GContext { g, always: false }, ty) {
475 generics.make_where_clause().predicates.push(
476 parse_quote_spanned! { ty.span() =>
477 #ty: #tr
478 },
479 );
480 }
481 }
482 }
483 Data::Enum(data) => {
484 for v in data.variants.iter() {
485 'field: for f in v.fields.iter() {
486 let ty = &f.ty;
487 let tr = quote!(::object_rainbow::ByteOrd);
488 for attr in &f.attrs {
489 if attr_str(attr).as_deref() == Some("output") {
490 let FieldOutputArgs { unchecked, .. } = attr.parse_args()?;
491 if unchecked {
492 continue 'field;
493 }
494 }
495 }
496 if type_contains_generics(GContext { g, always: false }, ty) {
497 generics.make_where_clause().predicates.push(
498 parse_quote_spanned! { ty.span() =>
499 #ty: #tr
500 },
501 );
502 }
503 }
504 }
505 generics.make_where_clause().predicates.push(parse_quote! {
506 <
507 <Self as ::object_rainbow::Enum>::Kind
508 as
509 ::object_rainbow::enumkind::EnumKind
510 >::Tag:
511 ::object_rainbow::ByteOrd + ::object_rainbow::InlineOutput
512 });
513 }
514 Data::Union(data) => {
515 return Err(Error::new_spanned(
516 data.union_token,
517 "`union`s are not supported",
518 ));
519 }
520 }
521 generics.make_where_clause().predicates.push(parse_quote! {
522 Self: ::core::cmp::PartialOrd + ::object_rainbow::ToOutput
523 });
524 Ok(generics)
525}
526
527fn let_self_other(fields: &syn::Fields, prefix: &str) -> proc_macro2::TokenStream {
528 match fields {
529 syn::Fields::Named(fields) => {
530 let fragments = fields.named.iter().map(|f| {
531 let ident = f.ident.as_ref().unwrap();
532 let prefixed_ident = Ident::new(&format!("{prefix}{ident}"), f.ty.span());
533 let colon = f.colon_token.unwrap();
534 quote! { #ident #colon #prefixed_ident }
535 });
536 quote! { {#(#fragments),*} }
537 }
538 syn::Fields::Unnamed(fields) => {
539 let fragments = fields.unnamed.iter().enumerate().map(|(i, f)| {
540 let prefixed_ident = Ident::new(&format!("{prefix}{i}"), f.ty.span());
541 quote! { #prefixed_ident }
542 });
543 quote! { (#(#fragments),*) }
544 }
545 syn::Fields::Unit => quote! {},
546 }
547}
548
549fn bytes_cmp_self_other(fields: &syn::Fields) -> proc_macro2::TokenStream {
550 let then = match fields {
551 syn::Fields::Named(fields) => {
552 let fragments = fields.named.iter().map(|f| {
553 let ident = f.ident.as_ref().unwrap();
554 let self_ident = Ident::new(&format!("__self_{ident}"), f.ty.span());
555 let other_ident = Ident::new(&format!("__other_{ident}"), f.ty.span());
556 quote! { .then_with(|| ::object_rainbow::ByteOrd::bytes_cmp(#self_ident, #other_ident)) }
557 });
558 quote! { #(#fragments)* }
559 }
560 syn::Fields::Unnamed(fields) => {
561 let fragments = fields.unnamed.iter().enumerate().map(|(i, f)| {
562 let self_ident = Ident::new(&format!("__self_{i}"), f.ty.span());
563 let other_ident = Ident::new(&format!("__other_{i}"), f.ty.span());
564 quote! { .then_with(|| ::object_rainbow::ByteOrd::bytes_cmp(#self_ident, #other_ident)) }
565 });
566 quote! { #(#fragments)* }
567 }
568 syn::Fields::Unit => quote! {},
569 };
570 quote! { ::core::cmp::Ordering::Equal #then }
571}
572
573fn gen_bytes_cmp(data: &Data) -> proc_macro2::TokenStream {
574 match data {
575 Data::Struct(data) => {
576 let let_self = let_self_other(&data.fields, "__self_");
577 let let_other = let_self_other(&data.fields, "__other_");
578 let bytes_cmp = bytes_cmp_self_other(&data.fields);
579 quote! {
580 match (self, other) {
581 (Self #let_self, Self #let_other) => #bytes_cmp,
582 }
583 }
584 }
585 Data::Enum(data) => {
586 let arms = data.variants.iter().map(|variant| {
587 let ident = &variant.ident;
588 let let_self = let_self_other(&variant.fields, "__self_");
589 let let_other = let_self_other(&variant.fields, "__other_");
590 let bytes_cmp = bytes_cmp_self_other(&variant.fields);
591 quote! {
592 (Self::#ident #let_self, Self::#ident #let_other) => #bytes_cmp,
593 (Self::#ident { .. }, _) => ::core::cmp::Ordering::Less,
594 (_, Self::#ident { .. }) => ::core::cmp::Ordering::Greater,
595 }
596 });
597 quote! {
598 match (self, other) {
599 #(#arms)*
600 }
601 }
602 }
603 Data::Union(data) => {
604 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
605 }
606 }
607}
608
609#[proc_macro_derive(ListHashes, attributes(topology, rainbow, hashes))]
629pub fn derive_list_hashes(input: TokenStream) -> TokenStream {
630 let input = parse_macro_input!(input as DeriveInput);
631 let name = input.ident;
632 let generics = input.generics.clone();
633 let (_, ty_generics, _) = generics.split_for_impl();
634 let generics = match bounds_list_hashes(input.generics, &input.data, &input.attrs) {
635 Ok(g) => g,
636 Err(e) => return e.into_compile_error().into(),
637 };
638 let list_hashes = gen_list_hashes(&input.data, &input.attrs);
639 let (impl_generics, _, where_clause) = generics.split_for_impl();
640 let target = parse_for(&name, &input.attrs);
641 let output = quote! {
642 #[automatically_derived]
643 impl #impl_generics ::object_rainbow::ListHashes for #target #ty_generics #where_clause {
644 fn list_hashes(&self, visitor: &mut (impl ?::core::marker::Sized + FnMut(::object_rainbow::Hash))) {
645 #list_hashes
646 }
647 }
648 };
649 TokenStream::from(output)
650}
651
652#[derive(Debug, FromMeta)]
653#[darling(derive_syn_parse)]
654struct ContainerHashesArgs {
655 #[darling(default)]
656 bound: Option<LitStr>,
657}
658
659#[derive(Debug, FromMeta)]
660#[darling(derive_syn_parse)]
661struct FieldHashesArgs {
662 #[darling(default)]
663 unchecked: bool,
664}
665
666fn parse_hashes_bounds(attrs: &[Attribute]) -> syn::Result<Vec<WherePredicate>> {
667 let mut wheres = Vec::new();
668 for attr in attrs {
669 if attr_str(attr).as_deref() == Some("hashes") {
670 let ContainerHashesArgs { bound } = attr.parse_args()?;
671 if let Some(bound) = bound {
672 wheres.push(bound.parse()?);
673 }
674 }
675 }
676 Ok(wheres)
677}
678
679fn bounds_list_hashes(
680 mut generics: Generics,
681 data: &Data,
682 attrs: &[Attribute],
683) -> syn::Result<Generics> {
684 let wheres = parse_hashes_bounds(attrs)?;
685 let g = &bounds_g(&generics);
686 match data {
687 Data::Struct(data) => {
688 'field: for f in data.fields.iter() {
689 let ty = &f.ty;
690 for attr in &f.attrs {
691 if attr_str(attr).as_deref() == Some("output") {
692 let FieldHashesArgs { unchecked, .. } = attr.parse_args()?;
693 if unchecked {
694 continue 'field;
695 }
696 }
697 }
698 if type_contains_generics(GContext { g, always: false }, ty) {
699 generics.make_where_clause().predicates.push(
700 parse_quote_spanned! { ty.span() =>
701 #ty: ::object_rainbow::ListHashes
702 },
703 );
704 }
705 }
706 }
707 Data::Enum(data) => {
708 for v in data.variants.iter() {
709 'field: for f in v.fields.iter() {
710 let ty = &f.ty;
711 for attr in &f.attrs {
712 if attr_str(attr).as_deref() == Some("output") {
713 let FieldHashesArgs { unchecked, .. } = attr.parse_args()?;
714 if unchecked {
715 continue 'field;
716 }
717 }
718 }
719 if type_contains_generics(GContext { g, always: false }, ty) {
720 generics.make_where_clause().predicates.push(
721 parse_quote_spanned! { ty.span() =>
722 #ty: ::object_rainbow::ListHashes
723 },
724 );
725 }
726 }
727 }
728 }
729 Data::Union(data) => {
730 return Err(Error::new_spanned(
731 data.union_token,
732 "`union`s are not supported",
733 ));
734 }
735 }
736 for bound in wheres {
737 generics.make_where_clause().predicates.push(bound);
738 }
739 Ok(generics)
740}
741
742fn fields_list_hashes(fields: &syn::Fields) -> proc_macro2::TokenStream {
743 match fields {
744 syn::Fields::Named(fields) => {
745 let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
746 let list_hashes = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
747 quote_spanned! { f.ty.span() =>
748 #i.list_hashes(visitor)
749 }
750 });
751 quote! {
752 { #(#let_self),* } => {
753 #(#list_hashes);*
754 }
755 }
756 }
757 syn::Fields::Unnamed(fields) => {
758 let let_self = fields
759 .unnamed
760 .iter()
761 .enumerate()
762 .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
763 let list_hashes = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
764 quote_spanned! { f.ty.span() =>
765 #i.list_hashes(visitor)
766 }
767 });
768 quote! {
769 (#(#let_self),*) => {
770 #(#list_hashes);*
771 }
772 }
773 }
774 syn::Fields::Unit => quote! {
775 => {}
776 },
777 }
778}
779
780fn gen_list_hashes(data: &Data, attrs: &[Attribute]) -> proc_macro2::TokenStream {
781 let untagged = match parse_untagged(attrs) {
782 Ok(untagged) => untagged,
783 Err(e) => return e.into_compile_error(),
784 };
785 match data {
786 Data::Struct(data) => {
787 let arm = fields_list_hashes(&data.fields);
788 quote! {
789 match self {
790 Self #arm
791 }
792 }
793 }
794 Data::Enum(data) => {
795 if data.variants.is_empty() {
796 return quote! {};
797 }
798 let to_output = data.variants.iter().map(|v| {
799 let ident = &v.ident;
800 let arm = fields_list_hashes(&v.fields);
801 quote! { Self::#ident #arm }
802 });
803 let tagged = if untagged.is_none() {
804 quote! {
805 let kind = ::object_rainbow::Enum::kind(self);
806 let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
807 tag.list_hashes(visitor);
808 }
809 } else {
810 quote! {}
811 };
812 quote! {
813 #tagged;
814 match self {
815 #(#to_output)*
816 }
817 }
818 }
819 Data::Union(data) => {
820 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
821 }
822 }
823}
824
825#[proc_macro_derive(Topological, attributes(topology))]
845pub fn derive_topological(input: TokenStream) -> TokenStream {
846 let input = parse_macro_input!(input as DeriveInput);
847 let name = input.ident;
848 let generics = input.generics.clone();
849 let (_, ty_generics, _) = generics.split_for_impl();
850 let generics = match bounds_topological(input.generics, &input.data, &input.attrs, &name) {
851 Ok(g) => g,
852 Err(e) => return e.into_compile_error().into(),
853 };
854 let traverse = gen_traverse(&input.data, &input.attrs);
855 let (impl_generics, _, where_clause) = generics.split_for_impl();
856 let target = parse_for(&name, &input.attrs);
857 let output = quote! {
858 const _: () = {
859 #[automatically_derived]
860 impl #impl_generics ::object_rainbow::Topological for #target #ty_generics
861 #where_clause
862 {
863 fn traverse(&self, visitor: &mut (impl ?::core::marker::Sized + ::object_rainbow::PointVisitor)) {
864 #traverse
865 }
866 }
867 };
868 };
869 TokenStream::from(output)
870}
871
872#[derive(Debug, FromMeta)]
873#[darling(derive_syn_parse)]
874struct ContainerTopologyArgs {
875 #[darling(default)]
876 recursive: bool,
877 #[darling(default)]
878 inline: bool,
879 #[darling(default)]
880 unchecked: bool,
881 #[darling(default)]
882 bound: Option<LitStr>,
883}
884
885fn parse_recursive_inline(
886 attrs: &[Attribute],
887) -> syn::Result<(bool, bool, bool, Vec<WherePredicate>)> {
888 let mut r = false;
889 let mut i = false;
890 let mut u = false;
891 let mut wheres = Vec::new();
892 for attr in attrs {
893 if attr_str(attr).as_deref() == Some("topology") {
894 let ContainerTopologyArgs {
895 recursive,
896 inline,
897 unchecked,
898 bound,
899 } = attr.parse_args()?;
900 if recursive {
901 r = true;
902 }
903 if inline {
904 i = true;
905 }
906 if unchecked {
907 u = true;
908 }
909 if let Some(bound) = bound {
910 wheres.push(bound.parse()?);
911 }
912 }
913 }
914 Ok((r, i, u, wheres))
915}
916
917#[derive(Debug, FromMeta)]
918#[darling(derive_syn_parse)]
919struct FieldTopologyArgs {
920 #[darling(default)]
921 unchecked: bool,
922 with: Option<Expr>,
923}
924
925fn bounds_topological(
926 mut generics: Generics,
927 data: &Data,
928 attrs: &[Attribute],
929 name: &Ident,
930) -> syn::Result<Generics> {
931 let (recursive, inline, u, wheres) = parse_recursive_inline(attrs)?;
932 let g = &bounds_g(&generics);
933 let bound = if recursive {
934 quote! { ::object_rainbow::Traversible }
935 } else {
936 quote! { ::object_rainbow::Topological }
937 };
938 match data {
939 Data::Struct(data) => {
940 'field: for f in data.fields.iter() {
941 let ty = &f.ty;
942 for attr in &f.attrs {
943 if attr_str(attr).as_deref() == Some("topology") {
944 let FieldTopologyArgs { unchecked, .. } = attr.parse_args()?;
945 if unchecked {
946 continue 'field;
947 }
948 }
949 }
950 if u {
951 continue 'field;
952 }
953 if type_contains_generics(GContext { g, always: false }, ty) {
954 generics.make_where_clause().predicates.push(
955 parse_quote_spanned! { ty.span() =>
956 #ty: #bound
957 },
958 );
959 }
960 }
961 }
962 Data::Enum(data) => {
963 for v in data.variants.iter() {
964 'field: for f in v.fields.iter() {
965 let ty = &f.ty;
966 for attr in &f.attrs {
967 if attr_str(attr).as_deref() == Some("topology") {
968 let FieldTopologyArgs { unchecked, .. } = attr.parse_args()?;
969 if unchecked {
970 continue 'field;
971 }
972 }
973 }
974 if u {
975 continue 'field;
976 }
977 if type_contains_generics(GContext { g, always: false }, ty) {
978 generics.make_where_clause().predicates.push(
979 parse_quote_spanned! { ty.span() =>
980 #ty: #bound
981 },
982 );
983 }
984 }
985 }
986 }
987 Data::Union(data) => {
988 return Err(Error::new_spanned(
989 data.union_token,
990 "`union`s are not supported",
991 ));
992 }
993 }
994 let output_bound = if inline {
995 quote! {
996 ::object_rainbow::InlineOutput
997 }
998 } else {
999 quote! {
1000 ::object_rainbow::ToOutput
1001 }
1002 };
1003 if recursive {
1004 generics
1005 .make_where_clause()
1006 .predicates
1007 .push(parse_quote_spanned! { name.span() =>
1008 Self: #output_bound + ::object_rainbow::Tagged
1009 });
1010 }
1011 for bound in wheres {
1012 generics.make_where_clause().predicates.push(bound);
1013 }
1014 Ok(generics)
1015}
1016
1017fn fields_traverse(fields: &syn::Fields) -> proc_macro2::TokenStream {
1018 match fields {
1019 syn::Fields::Named(fields) => {
1020 let let_self = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
1021 let traverse = let_self.clone().zip(fields.named.iter()).map(|(i, f)| {
1022 let mut w = None;
1023 for attr in &f.attrs {
1024 if attr_str(attr).as_deref() == Some("topology") {
1025 let FieldTopologyArgs { with, .. } = match attr.parse_args() {
1026 Ok(args) => args,
1027 Err(e) => return e.into_compile_error(),
1028 };
1029 if let Some(with) = with {
1030 w = Some(with);
1031 }
1032 }
1033 }
1034 if let Some(with) = w {
1035 quote_spanned! { f.ty.span() =>
1036 #with(#i, visitor)
1037 }
1038 } else {
1039 quote_spanned! { f.ty.span() =>
1040 #i.traverse(visitor)
1041 }
1042 }
1043 });
1044 quote! {
1045 { #(#let_self),* } => {
1046 #(#traverse);*
1047 }
1048 }
1049 }
1050 syn::Fields::Unnamed(fields) => {
1051 let let_self = fields
1052 .unnamed
1053 .iter()
1054 .enumerate()
1055 .map(|(i, f)| Ident::new(&format!("field{i}"), f.ty.span()));
1056 let traverse = let_self.clone().zip(fields.unnamed.iter()).map(|(i, f)| {
1057 let mut w = None;
1058 for attr in &f.attrs {
1059 if attr_str(attr).as_deref() == Some("topology") {
1060 let FieldTopologyArgs { with, .. } = match attr.parse_args() {
1061 Ok(args) => args,
1062 Err(e) => return e.into_compile_error(),
1063 };
1064 if let Some(with) = with {
1065 w = Some(with);
1066 }
1067 }
1068 }
1069 if let Some(with) = w {
1070 quote_spanned! { f.ty.span() =>
1071 #with(#i, visitor)
1072 }
1073 } else {
1074 quote_spanned! { f.ty.span() =>
1075 #i.traverse(visitor)
1076 }
1077 }
1078 });
1079 quote! {
1080 (#(#let_self),*) => {
1081 #(#traverse);*
1082 }
1083 }
1084 }
1085 syn::Fields::Unit => quote! {
1086 => {}
1087 },
1088 }
1089}
1090
1091fn gen_traverse(data: &Data, attrs: &[Attribute]) -> proc_macro2::TokenStream {
1092 let untagged = match parse_untagged(attrs) {
1093 Ok(untagged) => untagged,
1094 Err(e) => return e.into_compile_error(),
1095 };
1096 match data {
1097 Data::Struct(data) => {
1098 let arm = fields_traverse(&data.fields);
1099 quote! {
1100 match self {
1101 Self #arm
1102 }
1103 }
1104 }
1105 Data::Enum(data) => {
1106 if data.variants.is_empty() {
1107 return quote! {};
1108 }
1109 let to_output = data.variants.iter().map(|v| {
1110 let ident = &v.ident;
1111 let arm = fields_traverse(&v.fields);
1112 quote! { Self::#ident #arm }
1113 });
1114 let tagged = if untagged.is_none() {
1115 quote! {
1116 let kind = ::object_rainbow::Enum::kind(self);
1117 let tag = ::object_rainbow::enumkind::EnumKind::to_tag(kind);
1118 tag.traverse(visitor);
1119 }
1120 } else {
1121 quote! {}
1122 };
1123 quote! {
1124 #tagged;
1125 match self {
1126 #(#to_output)*
1127 }
1128 }
1129 }
1130 Data::Union(data) => {
1131 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
1132 }
1133 }
1134}
1135
1136#[proc_macro_derive(Tagged, attributes(tags))]
1156pub fn derive_tagged(input: TokenStream) -> TokenStream {
1157 let input = parse_macro_input!(input as DeriveInput);
1158 let name = input.ident;
1159 let mut errors = Vec::new();
1160 let generics = match bounds_tagged(input.generics, &input.data, &mut errors) {
1161 Ok(g) => g,
1162 Err(e) => return e.into_compile_error().into(),
1163 };
1164 let tags = gen_tags(&input.data, &input.attrs, &mut errors);
1165 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
1166 let errors = errors.into_iter().map(|e| e.into_compile_error());
1167 let target = parse_for(&name, &input.attrs);
1168 let output = quote! {
1169 #(#errors)*
1170
1171 #[automatically_derived]
1172 impl #impl_generics ::object_rainbow::Tagged for #target #ty_generics #where_clause {
1173 const TAGS: ::object_rainbow::Tags = #tags;
1174 }
1175 };
1176 TokenStream::from(output)
1177}
1178
1179#[derive(Debug, FromMeta)]
1180#[darling(derive_syn_parse)]
1181struct FieldTagArgs {
1182 #[darling(default)]
1183 skip: bool,
1184 replace: Option<Type>,
1185}
1186
1187fn bounds_tagged(
1188 mut generics: Generics,
1189 data: &Data,
1190 errors: &mut Vec<Error>,
1191) -> syn::Result<Generics> {
1192 let g = &bounds_g(&generics);
1193 match data {
1194 Data::Struct(data) => {
1195 for f in data.fields.iter() {
1196 let mut skip = false;
1197 let mut replace = Vec::new();
1198 for attr in &f.attrs {
1199 if attr_str(attr).as_deref() == Some("tags") {
1200 match attr.parse_args::<FieldTagArgs>() {
1201 Ok(args) => {
1202 skip |= args.skip;
1203 replace.extend(args.replace);
1204 }
1205 Err(e) => {
1206 errors.push(e);
1207 }
1208 }
1209 }
1210 }
1211 if !replace.is_empty() {
1212 for replace in replace {
1213 generics.make_where_clause().predicates.push(
1214 parse_quote_spanned! { replace.span() =>
1215 #replace: ::object_rainbow::Tagged
1216 },
1217 );
1218 }
1219 } else if !skip {
1220 let ty = &f.ty;
1221 if type_contains_generics(GContext { g, always: false }, ty) {
1222 generics.make_where_clause().predicates.push(
1223 parse_quote_spanned! { ty.span() =>
1224 #ty: ::object_rainbow::Tagged
1225 },
1226 );
1227 }
1228 }
1229 }
1230 }
1231 Data::Enum(data) => {
1232 for v in data.variants.iter() {
1233 for f in v.fields.iter() {
1234 let mut skip = false;
1235 let mut replace = Vec::new();
1236 for attr in &f.attrs {
1237 if attr_str(attr).as_deref() == Some("tags") {
1238 match attr.parse_args::<FieldTagArgs>() {
1239 Ok(args) => {
1240 skip |= args.skip;
1241 replace.extend(args.replace);
1242 }
1243 Err(e) => {
1244 errors.push(e);
1245 }
1246 }
1247 }
1248 }
1249 if !replace.is_empty() {
1250 for replace in replace {
1251 generics.make_where_clause().predicates.push(
1252 parse_quote_spanned! { replace.span() =>
1253 #replace: ::object_rainbow::Tagged
1254 },
1255 );
1256 }
1257 } else if !skip {
1258 let ty = &f.ty;
1259 if type_contains_generics(GContext { g, always: false }, ty) {
1260 generics.make_where_clause().predicates.push(
1261 parse_quote_spanned! { ty.span() =>
1262 #ty: ::object_rainbow::Tagged
1263 },
1264 );
1265 }
1266 }
1267 }
1268 }
1269 }
1270 Data::Union(data) => {
1271 return Err(Error::new_spanned(
1272 data.union_token,
1273 "`union`s are not supported",
1274 ));
1275 }
1276 }
1277 Ok(generics)
1278}
1279
1280struct StructTagArgs {
1281 tags: Vec<LitStr>,
1282}
1283
1284impl Parse for StructTagArgs {
1285 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
1286 let mut tags = Vec::new();
1287 while !input.is_empty() {
1288 let tag = input.parse::<LitStr>()?;
1289 tags.push(tag);
1290 if !input.is_empty() {
1291 input.parse::<Comma>()?;
1292 }
1293 }
1294 Ok(Self { tags })
1295 }
1296}
1297
1298fn fields_tags(fields: &syn::Fields) -> Vec<proc_macro2::TokenStream> {
1299 fields
1300 .iter()
1301 .filter_map(|f| {
1302 let mut skip = false;
1303 let mut replace = None;
1304 for attr in &f.attrs {
1305 if attr_str(attr).as_deref() == Some("tags") {
1306 let args = attr.parse_args::<FieldTagArgs>().ok()?;
1307 skip |= args.skip;
1308 replace = replace.or(args.replace);
1309 }
1310 }
1311 let ty = &f.ty;
1312 if let Some(replace) = replace {
1313 Some(quote! { <#replace as ::object_rainbow::Tagged>::TAGS })
1314 } else if !skip {
1315 Some(quote! { <#ty as ::object_rainbow::Tagged>::TAGS })
1316 } else {
1317 None
1318 }
1319 })
1320 .collect()
1321}
1322
1323fn gen_tags(data: &Data, attrs: &[Attribute], errors: &mut Vec<Error>) -> proc_macro2::TokenStream {
1324 let untagged = match parse_untagged(attrs) {
1325 Ok(untagged) => untagged,
1326 Err(e) => return e.into_compile_error(),
1327 };
1328 match data {
1329 Data::Struct(data) => {
1330 let mut tags = Vec::new();
1331 for attr in attrs {
1332 if attr_str(attr).as_deref() == Some("tags") {
1333 match attr.parse_args::<StructTagArgs>() {
1334 Ok(mut args) => tags.append(&mut args.tags),
1335 Err(e) => errors.push(e),
1336 }
1337 }
1338 }
1339 let nested = fields_tags(&data.fields);
1340 if nested.len() == 1 && tags.is_empty() {
1341 let nested = nested.into_iter().next().unwrap();
1342 quote! {
1343 #nested
1344 }
1345 } else {
1346 quote! {
1347 ::object_rainbow::Tags(&[#(#tags),*], &[#(&#nested),*])
1348 }
1349 }
1350 }
1351 Data::Enum(data) => {
1352 let mut tags = Vec::new();
1353 for attr in attrs {
1354 if attr_str(attr).as_deref() == Some("tags") {
1355 match attr.parse_args::<StructTagArgs>() {
1356 Ok(mut args) => tags.append(&mut args.tags),
1357 Err(e) => errors.push(e),
1358 }
1359 }
1360 }
1361 let mut nested: Vec<_> = data
1362 .variants
1363 .iter()
1364 .flat_map(|v| fields_tags(&v.fields))
1365 .collect();
1366 let kind_tags = quote! {
1367 <
1368 <
1369 <
1370 Self
1371 as
1372 ::object_rainbow::Enum
1373 >::Kind
1374 as
1375 ::object_rainbow::enumkind::EnumKind
1376 >::Tag
1377 as ::object_rainbow::Tagged
1378 >::TAGS
1379 };
1380 if untagged.is_none() {
1381 nested.insert(0, kind_tags);
1382 }
1383 if nested.len() == 1 && tags.is_empty() {
1384 let nested = nested.into_iter().next().unwrap();
1385 quote! {
1386 #nested
1387 }
1388 } else {
1389 quote! {
1390 ::object_rainbow::Tags(&[#(#tags),*], &[#(&#nested),*])
1391 }
1392 }
1393 }
1394 Data::Union(data) => {
1395 Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1396 }
1397 }
1398}
1399
1400#[proc_macro_derive(Size)]
1422pub fn derive_size(input: TokenStream) -> TokenStream {
1423 let input = parse_macro_input!(input as DeriveInput);
1424 let name = input.ident;
1425 let size_arr = gen_size_arr(&input.data);
1426 let size = gen_size(&input.data);
1427 let mut original_generics = input.generics.clone();
1428 let (generics, needs_output) = match bounds_size(input.generics.clone(), &input.data, &size_arr)
1429 {
1430 Ok(g) => g,
1431 Err(e) => return e.into_compile_error().into(),
1432 };
1433 let generics_array = generics.clone();
1434 let (_, _, where_clause_array) = generics_array.split_for_impl();
1435 original_generics
1436 .make_where_clause()
1437 .predicates
1438 .push(parse_quote!(
1439 Self: ::object_rainbow::SizeSumHelper<
1440 SizeArray: ::object_rainbow::typenum::FoldAdd<
1441 Output: ::object_rainbow::typenum::Unsigned
1442 >
1443 >
1444 ));
1445 let (impl_generics, ty_generics, where_clause) = original_generics.split_for_impl();
1446 let mut generics = input.generics;
1447 if needs_output {
1448 generics.params.push(parse_quote!(
1449 __Output: ::object_rainbow::typenum::Unsigned
1450 ));
1451 }
1452 let (impl_generics_array, _, _) = generics.split_for_impl();
1453 let target = parse_for(&name, &input.attrs);
1454 let output = quote! {
1455 const _: () = {
1456 use ::object_rainbow::typenum::tarr;
1457
1458 #[automatically_derived]
1459 impl #impl_generics_array ::object_rainbow::SizeSumHelper
1460 for #target #ty_generics #where_clause_array {
1461 const SIZE_ARRAY: usize = #size;
1462 type SizeArray = #size_arr;
1463 }
1464
1465 #[automatically_derived]
1466 impl #impl_generics ::object_rainbow::Size for #target #ty_generics #where_clause {
1467 const SIZE: usize = <Self as ::object_rainbow::SizeSumHelper>::SIZE_ARRAY;
1468 type Size = <
1469 <Self as ::object_rainbow::SizeSumHelper>::SizeArray
1470 as
1471 ::object_rainbow::typenum::FoldAdd
1472 >::Output;
1473 }
1474 };
1475 };
1476 TokenStream::from(output)
1477}
1478
1479fn bounds_size(
1480 mut generics: Generics,
1481 data: &Data,
1482 size_arr: &proc_macro2::TokenStream,
1483) -> syn::Result<(Generics, bool)> {
1484 let g = &bounds_g(&generics);
1485 let is_enum = match data {
1486 Data::Struct(data) => {
1487 for f in data.fields.iter() {
1488 let ty = &f.ty;
1489 if type_contains_generics(GContext { g, always: false }, ty) {
1490 generics.make_where_clause().predicates.push(
1491 parse_quote_spanned! { ty.span() =>
1492 #ty: ::object_rainbow::Size
1493 },
1494 );
1495 }
1496 }
1497 if generics.params.is_empty() {
1498 generics.make_where_clause().predicates.push(parse_quote!(
1499 #size_arr: ::object_rainbow::typenum::FoldAdd<
1500 Output: ::object_rainbow::typenum::Unsigned
1501 >
1502 ));
1503 false
1504 } else {
1505 generics.make_where_clause().predicates.push(parse_quote!(
1506 #size_arr: ::object_rainbow::typenum::FoldAdd<
1507 Output = __Output
1508 >
1509 ));
1510 true
1511 }
1512 }
1513 Data::Enum(data) => {
1514 for v in data.variants.iter() {
1515 for f in v.fields.iter() {
1516 let ty = &f.ty;
1517 if type_contains_generics(GContext { g, always: false }, ty) {
1518 generics.make_where_clause().predicates.push(
1519 parse_quote_spanned! { ty.span() =>
1520 #ty: ::object_rainbow::Size
1521 },
1522 );
1523 }
1524 }
1525 }
1526 for v in data.variants.iter().skip(1) {
1527 let arr = fields_size_arr(&v.fields, true);
1528 generics.make_where_clause().predicates.push(parse_quote!(
1529 #arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
1530 ));
1531 }
1532 generics.make_where_clause().predicates.push(parse_quote!(
1533 #size_arr: ::object_rainbow::typenum::FoldAdd<Output = __Output>
1534 ));
1535 true
1536 }
1537 Data::Union(data) => {
1538 return Err(Error::new_spanned(
1539 data.union_token,
1540 "`union`s are not supported",
1541 ));
1542 }
1543 };
1544 Ok((generics, is_enum))
1545}
1546
1547fn fields_size_arr(fields: &syn::Fields, as_enum: bool) -> proc_macro2::TokenStream {
1548 let kind_size = quote! {
1549 <
1550 <
1551 <
1552 Self
1553 as
1554 ::object_rainbow::Enum
1555 >::Kind
1556 as
1557 ::object_rainbow::enumkind::EnumKind
1558 >::Tag
1559 as ::object_rainbow::Size
1560 >::Size
1561 };
1562 if fields.is_empty() {
1563 return if as_enum {
1564 quote! { tarr![#kind_size, ::object_rainbow::typenum::consts::U0] }
1565 } else {
1566 quote! { tarr![::object_rainbow::typenum::consts::U0] }
1567 };
1568 }
1569 let size_arr = fields.iter().map(|f| {
1570 let ty = &f.ty;
1571 quote! { <#ty as ::object_rainbow::Size>::Size }
1572 });
1573 if as_enum {
1574 quote! { tarr![#kind_size, ::object_rainbow::typenum::consts::U0, #(#size_arr),*] }
1575 } else {
1576 quote! { tarr![::object_rainbow::typenum::consts::U0, #(#size_arr),*] }
1577 }
1578}
1579
1580fn gen_size_arr(data: &Data) -> proc_macro2::TokenStream {
1581 match data {
1582 Data::Struct(data) => fields_size_arr(&data.fields, false),
1583 Data::Enum(data) => {
1584 if let Some(v) = data.variants.first() {
1585 fields_size_arr(&v.fields, true)
1586 } else {
1587 Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
1588 .into_compile_error()
1589 }
1590 }
1591 Data::Union(data) => {
1592 Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1593 }
1594 }
1595}
1596
1597fn fields_size(fields: &syn::Fields) -> proc_macro2::TokenStream {
1598 if fields.is_empty() {
1599 return quote! {0};
1600 }
1601 let size = fields.iter().map(|f| {
1602 let ty = &f.ty;
1603 quote! { <#ty as ::object_rainbow::Size>::SIZE }
1604 });
1605 quote! {
1606 #(#size)+*
1607 }
1608}
1609
1610fn gen_size(data: &Data) -> proc_macro2::TokenStream {
1611 match data {
1612 Data::Struct(data) => fields_size(&data.fields),
1613 Data::Enum(data) => {
1614 if let Some(v) = data.variants.first() {
1615 let size = fields_size(&v.fields);
1616 let kind_size = quote! {
1617 <
1618 <
1619 <
1620 Self
1621 as
1622 ::object_rainbow::Enum
1623 >::Kind
1624 as
1625 ::object_rainbow::enumkind::EnumKind
1626 >::Tag
1627 as ::object_rainbow::Size
1628 >::SIZE
1629 };
1630 quote! { #kind_size + #size }
1631 } else {
1632 Error::new_spanned(data.enum_token, "empty `enum`s are not supported")
1633 .into_compile_error()
1634 }
1635 }
1636 Data::Union(data) => {
1637 Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
1638 }
1639 }
1640}
1641
1642#[proc_macro_derive(Parse, attributes(parse))]
1663pub fn derive_parse(input: TokenStream) -> TokenStream {
1664 let input = parse_macro_input!(input as DeriveInput);
1665 let name = input.ident;
1666 let generics = input.generics.clone();
1667 let (_, ty_generics, _) = generics.split_for_impl();
1668 let (inp, generics) = match bounds_parse(input.generics, &input.data, &input.attrs) {
1669 Ok(g) => g,
1670 Err(e) => return e.into_compile_error().into(),
1671 };
1672 let (parse, enum_parse) = gen_parse(&input.data, &input.attrs);
1673 let (impl_generics, _, where_clause) = generics.split_for_impl();
1674 let target = parse_for(&name, &input.attrs);
1675 let enum_parse = enum_parse.map(|enum_parse| {
1676 quote! {
1677 #[automatically_derived]
1678 impl #impl_generics ::object_rainbow::enumkind::EnumParse<#inp> for #target #ty_generics
1679 #where_clause
1680 {
1681 fn enum_parse(
1682 kind: <Self as ::object_rainbow::Enum>::Kind, mut input: #inp,
1683 ) -> ::object_rainbow::Result<Self> {
1684 #enum_parse
1685 }
1686 }
1687 }
1688 });
1689 let output = quote! {
1690 const _: () = {
1691 #[automatically_derived]
1692 impl #impl_generics ::object_rainbow::Parse<#inp> for #target #ty_generics
1693 #where_clause
1694 {
1695 fn parse(mut input: #inp) -> ::object_rainbow::Result<Self> {
1696 #parse
1697 }
1698 }
1699
1700 #enum_parse
1701 };
1702 };
1703 TokenStream::from(output)
1704}
1705
1706#[derive(Debug, FromMeta)]
1707#[darling(derive_syn_parse)]
1708struct ContainerParseArgs {
1709 #[darling(default)]
1710 unchecked: bool,
1711 #[darling(default)]
1712 bound: Option<LitStr>,
1713 #[darling(default)]
1714 generic: Option<LitStr>,
1715 #[darling(default)]
1716 input: Option<LitStr>,
1717}
1718
1719fn parse_parse_args(
1720 attrs: &[Attribute],
1721) -> syn::Result<(bool, Ident, Vec<WherePredicate>, Vec<GenericParam>)> {
1722 let mut u = false;
1723 let mut inp = parse_quote!(__I);
1724 let mut wheres = Vec::new();
1725 let mut ig = Vec::new();
1726 for attr in attrs {
1727 if attr_str(attr).as_deref() == Some("parse") {
1728 let ContainerParseArgs {
1729 unchecked,
1730 input,
1731 bound,
1732 generic,
1733 } = attr.parse_args()?;
1734 if unchecked {
1735 u = true;
1736 }
1737 if let Some(input) = input {
1738 inp = input.parse()?;
1739 }
1740 if let Some(bound) = bound {
1741 wheres.push(bound.parse()?);
1742 }
1743 if let Some(generic) = generic {
1744 ig.push(generic.parse()?);
1745 }
1746 }
1747 }
1748 Ok((u, inp, wheres, ig))
1749}
1750
1751#[derive(Debug, FromMeta)]
1752#[darling(derive_syn_parse)]
1753struct ParseArgs {
1754 #[darling(default)]
1755 unchecked: bool,
1756 with: Option<Expr>,
1757}
1758
1759fn bounds_parse(
1760 mut generics: Generics,
1761 data: &Data,
1762 attrs: &[Attribute],
1763) -> syn::Result<(Ident, Generics)> {
1764 let (recursive, _, _, _) = parse_recursive_inline(attrs)?;
1765 let (u, inp, wheres, ig) = parse_parse_args(attrs)?;
1766 let tr = |last| match (last, recursive) {
1767 (true, true) => {
1768 quote!(::object_rainbow::Parse<#inp> + ::object_rainbow::Object<#inp::Extra>)
1769 }
1770 (true, false) => quote!(::object_rainbow::Parse<#inp>),
1771 (false, true) => {
1772 quote!(::object_rainbow::ParseInline<#inp> + ::object_rainbow::Inline<#inp::Extra>)
1773 }
1774 (false, false) => quote!(::object_rainbow::ParseInline<#inp>),
1775 };
1776 match data {
1777 Data::Struct(data) => {
1778 let last_at = data.fields.len().saturating_sub(1);
1779 'field: for (i, f) in data.fields.iter().enumerate() {
1780 let last = i == last_at;
1781 let ty = &f.ty;
1782 for attr in &f.attrs {
1783 if attr_str(attr).as_deref() == Some("parse") {
1784 let ParseArgs { unchecked, .. } = attr.parse_args::<ParseArgs>()?;
1785 if unchecked {
1786 continue 'field;
1787 }
1788 }
1789 }
1790 if u {
1791 continue 'field;
1792 }
1793 let tr = tr(last);
1794 generics
1795 .make_where_clause()
1796 .predicates
1797 .push(parse_quote_spanned! { ty.span() =>
1798 #ty: #tr
1799 });
1800 }
1801 }
1802 Data::Enum(data) => {
1803 for v in data.variants.iter() {
1804 let last_at = v.fields.len().saturating_sub(1);
1805 'field: for (i, f) in v.fields.iter().enumerate() {
1806 let ty = &f.ty;
1807 for attr in &f.attrs {
1808 if attr_str(attr).as_deref() == Some("parse") {
1809 let ParseArgs { unchecked, .. } = attr.parse_args::<ParseArgs>()?;
1810 if unchecked {
1811 continue 'field;
1812 }
1813 }
1814 }
1815 if u {
1816 continue 'field;
1817 }
1818 let last = i == last_at;
1819 let tr = tr(last);
1820 generics.make_where_clause().predicates.push(
1821 parse_quote_spanned! { ty.span() =>
1822 #ty: #tr
1823 },
1824 );
1825 }
1826 }
1827 }
1828 Data::Union(data) => {
1829 return Err(Error::new_spanned(
1830 data.union_token,
1831 "`union`s are not supported",
1832 ));
1833 }
1834 }
1835 generics.params.push(if recursive {
1836 parse_quote!(#inp: ::object_rainbow::PointInput<
1837 Extra: ::core::marker::Send + ::core::marker::Sync + ::core::clone::Clone
1838 >)
1839 } else {
1840 parse_quote!(#inp: ::object_rainbow::ParseInput)
1841 });
1842 for bound in wheres {
1843 generics.make_where_clause().predicates.push(bound);
1844 }
1845 generics.params.extend(ig);
1846 Ok((inp, generics))
1847}
1848
1849fn gen_parse(
1850 data: &Data,
1851 attrs: &[Attribute],
1852) -> (proc_macro2::TokenStream, Option<proc_macro2::TokenStream>) {
1853 match parse_untagged(attrs) {
1854 Ok(None) => {}
1855 Ok(Some(untagged)) => {
1856 return (
1857 syn::Error::new(untagged.span(), "`untagged` cannot be parsed")
1858 .into_compile_error(),
1859 None,
1860 );
1861 }
1862 Err(e) => return (e.into_compile_error(), None),
1863 };
1864 match data {
1865 Data::Struct(data) => {
1866 let arm = fields_parse(&data.fields);
1867 (quote! { Ok(Self #arm)}, None)
1868 }
1869 Data::Enum(data) => {
1870 let parse = data.variants.iter().map(|v| {
1871 let ident = &v.ident;
1872 let arm = fields_parse(&v.fields);
1873 quote! {
1874 <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
1875 }
1876 });
1877 (
1878 quote! {
1879 ::object_rainbow::enumkind::EnumParse::parse_as_enum(input)
1880 },
1881 Some(if data.variants.is_empty() {
1882 quote! {
1883 match kind {}
1884 }
1885 } else {
1886 quote! {
1887 Ok(match kind {
1888 #(#parse)*
1889 })
1890 }
1891 }),
1892 )
1893 }
1894 Data::Union(data) => (
1895 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error(),
1896 None,
1897 ),
1898 }
1899}
1900
1901fn fields_parse(fields: &syn::Fields) -> proc_macro2::TokenStream {
1902 let last_at = fields.len().saturating_sub(1);
1903 match fields {
1904 syn::Fields::Named(fields) => {
1905 let parse = fields.named.iter().enumerate().map(|(i, f)| {
1906 let last = i == last_at;
1907 let mut w = None;
1908 for attr in &f.attrs {
1909 if attr_str(attr).as_deref() == Some("parse") {
1910 let ParseArgs { with, .. } = match attr.parse_args::<ParseArgs>() {
1911 Ok(args) => args,
1912 Err(e) => return e.into_compile_error(),
1913 };
1914 if let Some(with) = with {
1915 w = Some(with);
1916 }
1917 }
1918 }
1919 let i = f.ident.as_ref().unwrap();
1920 if let Some(with) = w {
1921 let arg = if last {
1922 quote!(input)
1923 } else {
1924 quote!(&mut input)
1925 };
1926 quote_spanned! { f.ty.span() =>
1927 #i: #with(#arg)?
1928 }
1929 } else {
1930 let method = if last {
1931 quote!(parse)
1932 } else {
1933 quote!(parse_inline)
1934 };
1935 quote_spanned! { f.ty.span() =>
1936 #i: input.#method()?
1937 }
1938 }
1939 });
1940 quote! { { #(#parse),* } }
1941 }
1942 syn::Fields::Unnamed(fields) => {
1943 let parse = fields.unnamed.iter().enumerate().map(|(i, f)| {
1944 let mut w = None;
1945 for attr in &f.attrs {
1946 if attr_str(attr).as_deref() == Some("parse") {
1947 let ParseArgs { with, .. } = match attr.parse_args::<ParseArgs>() {
1948 Ok(args) => args,
1949 Err(e) => return e.into_compile_error(),
1950 };
1951 if let Some(with) = with {
1952 w = Some(with);
1953 }
1954 }
1955 }
1956 let last = i == last_at;
1957 if let Some(with) = w {
1958 let arg = if last {
1959 quote!(input)
1960 } else {
1961 quote!(&mut input)
1962 };
1963 quote_spanned! { f.ty.span() =>
1964 #with(#arg)?
1965 }
1966 } else {
1967 let method = if last {
1968 quote!(parse)
1969 } else {
1970 quote!(parse_inline)
1971 };
1972 quote_spanned! { f.ty.span() =>
1973 input.#method()?
1974 }
1975 }
1976 });
1977 quote! { (#(#parse),*) }
1978 }
1979 syn::Fields::Unit => quote! {},
1980 }
1981}
1982
1983#[proc_macro_derive(ParseInline, attributes(parse))]
2004pub fn derive_parse_inline(input: TokenStream) -> TokenStream {
2005 let input = parse_macro_input!(input as DeriveInput);
2006 let name = input.ident;
2007 let generics = input.generics.clone();
2008 let (_, ty_generics, _) = generics.split_for_impl();
2009 let (inp, generics) = match bounds_parse_inline(input.generics, &input.data, &input.attrs) {
2010 Ok(g) => g,
2011 Err(e) => return e.into_compile_error().into(),
2012 };
2013 let (parse_inline, enum_parse_inline) = gen_parse_inline(&input.data);
2014 let (impl_generics, _, where_clause) = generics.split_for_impl();
2015 let target = parse_for(&name, &input.attrs);
2016 let enum_parse_inline = enum_parse_inline.map(|enum_parse_inline| {
2017 quote! {
2018 #[automatically_derived]
2019 impl #impl_generics ::object_rainbow::enumkind::EnumParseInline<#inp>
2020 for #target #ty_generics #where_clause {
2021 fn enum_parse_inline(
2022 kind: <Self as ::object_rainbow::Enum>::Kind, input: &mut #inp,
2023 ) -> ::object_rainbow::Result<Self> {
2024 #enum_parse_inline
2025 }
2026 }
2027 }
2028 });
2029 let output = quote! {
2030 #[automatically_derived]
2031 impl #impl_generics ::object_rainbow::ParseInline<#inp>
2032 for #target #ty_generics #where_clause {
2033 fn parse_inline(input: &mut #inp) -> ::object_rainbow::Result<Self> {
2034 #parse_inline
2035 }
2036 }
2037
2038 #enum_parse_inline
2039 };
2040 TokenStream::from(output)
2041}
2042
2043fn bounds_parse_inline(
2044 mut generics: Generics,
2045 data: &Data,
2046 attrs: &[Attribute],
2047) -> syn::Result<(Ident, Generics)> {
2048 let (recursive, _, _, _) = parse_recursive_inline(attrs)?;
2049 let (u, inp, wheres, ig) = parse_parse_args(attrs)?;
2050 let tr = if recursive {
2051 quote!(::object_rainbow::ParseInline<#inp> + ::object_rainbow::Inline<#inp::Extra>)
2052 } else {
2053 quote!(::object_rainbow::ParseInline<#inp>)
2054 };
2055 match data {
2056 Data::Struct(data) => {
2057 'field: for f in data.fields.iter() {
2058 let ty = &f.ty;
2059 for attr in &f.attrs {
2060 if attr_str(attr).as_deref() == Some("parse") {
2061 let ParseArgs { unchecked, .. } = attr.parse_args::<ParseArgs>()?;
2062 if unchecked {
2063 continue 'field;
2064 }
2065 }
2066 }
2067 if u {
2068 continue 'field;
2069 }
2070 generics
2071 .make_where_clause()
2072 .predicates
2073 .push(parse_quote_spanned! { ty.span() =>
2074 #ty: #tr
2075 });
2076 }
2077 }
2078 Data::Enum(data) => {
2079 for v in data.variants.iter() {
2080 'field: for f in v.fields.iter() {
2081 let ty = &f.ty;
2082 for attr in &f.attrs {
2083 if attr_str(attr).as_deref() == Some("parse") {
2084 let ParseArgs { unchecked, .. } = attr.parse_args::<ParseArgs>()?;
2085 if unchecked {
2086 continue 'field;
2087 }
2088 }
2089 }
2090 if u {
2091 continue 'field;
2092 }
2093 generics.make_where_clause().predicates.push(
2094 parse_quote_spanned! { ty.span() =>
2095 #ty: #tr
2096 },
2097 );
2098 }
2099 }
2100 }
2101 Data::Union(data) => {
2102 return Err(Error::new_spanned(
2103 data.union_token,
2104 "`union`s are not supported",
2105 ));
2106 }
2107 }
2108 generics.params.push(if recursive {
2109 parse_quote!(#inp: ::object_rainbow::PointInput<
2110 Extra: ::core::marker::Send + ::core::marker::Sync
2111 >)
2112 } else {
2113 parse_quote!(#inp: ::object_rainbow::ParseInput)
2114 });
2115 for bound in wheres {
2116 generics.make_where_clause().predicates.push(bound);
2117 }
2118 for generic in ig {
2119 generics.params.push(parse_quote!(#generic));
2120 }
2121 Ok((inp, generics))
2122}
2123
2124fn fields_parse_inline(fields: &syn::Fields) -> proc_macro2::TokenStream {
2125 match fields {
2126 syn::Fields::Named(fields) => {
2127 let parse = fields.named.iter().map(|f| {
2128 let i = f.ident.as_ref().unwrap();
2129 quote_spanned! { f.ty.span() =>
2130 #i: input.parse_inline()?
2131 }
2132 });
2133 quote! { { #(#parse),* } }
2134 }
2135 syn::Fields::Unnamed(fields) => {
2136 let parse = fields.unnamed.iter().map(|f| {
2137 quote_spanned! { f.ty.span() =>
2138 input.parse_inline()?
2139 }
2140 });
2141 quote! { (#(#parse),*) }
2142 }
2143 syn::Fields::Unit => quote! {},
2144 }
2145}
2146
2147fn gen_parse_inline(data: &Data) -> (proc_macro2::TokenStream, Option<proc_macro2::TokenStream>) {
2148 match data {
2149 Data::Struct(data) => {
2150 let arm = fields_parse_inline(&data.fields);
2151 (quote! { Ok(Self #arm) }, None)
2152 }
2153 Data::Enum(data) => {
2154 let parse_inline = data.variants.iter().map(|v| {
2155 let ident = &v.ident;
2156 let arm = fields_parse_inline(&v.fields);
2157 quote! {
2158 <Self as ::object_rainbow::Enum>::Kind::#ident => Self::#ident #arm,
2159 }
2160 });
2161 (
2162 quote! {
2163 ::object_rainbow::enumkind::EnumParseInline::parse_as_inline_enum(input)
2164 },
2165 Some(if data.variants.is_empty() {
2166 quote! {
2167 match kind {}
2168 }
2169 } else {
2170 quote! {
2171 Ok(match kind {
2172 #(#parse_inline)*
2173 })
2174 }
2175 }),
2176 )
2177 }
2178 Data::Union(data) => (
2179 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error(),
2180 None,
2181 ),
2182 }
2183}
2184
2185#[proc_macro_derive(ParseAsInline)]
2202pub fn derive_parse_as_inline(input: TokenStream) -> TokenStream {
2203 let input = parse_macro_input!(input as DeriveInput);
2204 let name = input.ident;
2205 let generics = input.generics.clone();
2206 let (_, ty_generics, _) = generics.split_for_impl();
2207 let generics = match bounds_parse_as_inline(input.generics, &name) {
2208 Ok(g) => g,
2209 Err(e) => return e.into_compile_error().into(),
2210 };
2211 let (impl_generics, _, where_clause) = generics.split_for_impl();
2212 let target = parse_for(&name, &input.attrs);
2213 let output = quote! {
2214 #[automatically_derived]
2215 impl #impl_generics ::object_rainbow::Parse<__I> for #target #ty_generics #where_clause {
2216 fn parse(input: __I) -> ::object_rainbow::Result<Self> {
2217 ::object_rainbow::ParseInline::<__I>::parse_as_inline(input)
2218 }
2219 }
2220 };
2221 TokenStream::from(output)
2222}
2223
2224fn bounds_parse_as_inline(mut generics: Generics, name: &Ident) -> syn::Result<Generics> {
2225 generics
2226 .make_where_clause()
2227 .predicates
2228 .push(parse_quote_spanned! { name.span() =>
2229 Self: ::object_rainbow::ParseInline::<__I>
2230 });
2231 generics
2232 .params
2233 .push(parse_quote!(__I: ::object_rainbow::ParseInput));
2234 Ok(generics)
2235}
2236
2237fn parse_path(attr: &Attribute) -> syn::Result<Type> {
2238 attr.parse_args::<LitStr>()?.parse()
2239}
2240
2241fn attr_str(attr: &Attribute) -> Option<String> {
2242 Some(attr.path().get_ident()?.to_string())
2243}
2244
2245#[proc_macro_derive(Enum, attributes(enumtag))]
2329pub fn derive_enum(input: TokenStream) -> TokenStream {
2330 let input = parse_macro_input!(input as DeriveInput);
2331 let name = input.ident;
2332 let generics = input.generics.clone();
2333 let (_, ty_generics, _) = generics.split_for_impl();
2334 let generics = input.generics;
2335 let length = gen_length(&input.data);
2336 let variants = gen_variants(&input.data);
2337 let variant_count = gen_variant_count(&input.data);
2338 let to_tag = gen_to_tag(&input.data);
2339 let from_tag = gen_from_tag(&input.data);
2340 let kind = gen_kind(&input.data);
2341 let (impl_generics, _, where_clause) = generics.split_for_impl();
2342 let mut errors = Vec::new();
2343 let mut enumtag = None;
2344 for attr in &input.attrs {
2345 if attr_str(attr).as_deref() == Some("enumtag") {
2346 match parse_path(attr) {
2347 Ok(path) => {
2348 if enumtag.is_some() {
2349 errors.push(Error::new_spanned(path, "duplicate tag"));
2350 } else {
2351 enumtag = Some(path);
2352 }
2353 }
2354 Err(e) => errors.push(e),
2355 }
2356 }
2357 }
2358 let enumtag = enumtag.unwrap_or_else(|| {
2359 parse_quote!(
2360 ::object_rainbow::partial_byte_tag::PartialByteTag<#length>
2361 )
2362 });
2363 let errors = errors.into_iter().map(|e| e.into_compile_error());
2364 let target = parse_for(&name, &input.attrs);
2365 let output = quote! {
2366 const _: () = {
2367 #(#errors)*
2368
2369 use ::object_rainbow::enumkind::EnumKind;
2370
2371 #[derive(
2372 ::core::clone::Clone,
2373 ::core::marker::Copy,
2374 ::object_rainbow::ParseAsInline,
2375 )]
2376 pub enum __Kind {
2377 #variants
2378 }
2379
2380 #[automatically_derived]
2381 impl ::object_rainbow::enumkind::EnumKind for __Kind {
2382 type Tag = ::object_rainbow::enumkind::EnumTag<
2383 #enumtag,
2384 #variant_count,
2385 >;
2386
2387 fn to_tag(self) -> Self::Tag {
2388 #to_tag
2389 }
2390
2391 fn from_tag(tag: Self::Tag) -> Self {
2392 #from_tag
2393 }
2394 }
2395
2396 impl<I: ::object_rainbow::ParseInput> ::object_rainbow::ParseInline<I> for __Kind {
2397 fn parse_inline(input: &mut I) -> ::object_rainbow::Result<Self> {
2398 Ok(::object_rainbow::enumkind::EnumKind::from_tag(input.parse_inline()?))
2399 }
2400 }
2401
2402 impl ::object_rainbow::MaybeHasNiche for __Kind {
2403 type MnArray = <#enumtag as ::object_rainbow::MaybeHasNiche>::MnArray;
2404 }
2405
2406 #[automatically_derived]
2407 impl #impl_generics ::object_rainbow::Enum for #target #ty_generics #where_clause {
2408 type Kind = __Kind;
2409
2410 fn kind(&self) -> Self::Kind {
2411 #kind
2412 }
2413 }
2414 };
2415 };
2416 TokenStream::from(output)
2417}
2418
2419fn gen_length(data: &Data) -> proc_macro2::TokenStream {
2420 match data {
2421 Data::Struct(data) => {
2422 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2423 }
2424 Data::Enum(data) => {
2425 let name = format!("U{}", data.variants.len());
2426 let ident = Ident::new(&name, data.variants.span());
2427 quote! { ::object_rainbow::typenum::#ident }
2428 }
2429 Data::Union(data) => {
2430 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2431 }
2432 }
2433}
2434
2435fn gen_variants(data: &Data) -> proc_macro2::TokenStream {
2436 match data {
2437 Data::Struct(data) => {
2438 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2439 }
2440 Data::Enum(data) => {
2441 let variants = data.variants.iter().map(|v| &v.ident);
2442 quote! { #(#variants),* }
2443 }
2444 Data::Union(data) => {
2445 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2446 }
2447 }
2448}
2449
2450fn gen_variant_count(data: &Data) -> proc_macro2::TokenStream {
2451 match data {
2452 Data::Struct(data) => {
2453 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2454 }
2455 Data::Enum(data) => {
2456 let variant_count = data.variants.len();
2457 quote! { #variant_count }
2458 }
2459 Data::Union(data) => {
2460 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2461 }
2462 }
2463}
2464
2465fn gen_to_tag(data: &Data) -> proc_macro2::TokenStream {
2466 match data {
2467 Data::Struct(data) => {
2468 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2469 }
2470 Data::Enum(data) => {
2471 let to_tag = data.variants.iter().enumerate().map(|(i, v)| {
2472 let ident = &v.ident;
2473 quote_spanned! { ident.span() =>
2474 Self::#ident => ::object_rainbow::enumkind::EnumTag::from_const::<#i>(),
2475 }
2476 });
2477 quote! {
2478 match self {
2479 #(#to_tag)*
2480 }
2481 }
2482 }
2483 Data::Union(data) => {
2484 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2485 }
2486 }
2487}
2488
2489fn gen_from_tag(data: &Data) -> proc_macro2::TokenStream {
2490 match data {
2491 Data::Struct(data) => {
2492 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2493 }
2494 Data::Enum(data) => {
2495 let from_tag = data.variants.iter().enumerate().map(|(i, v)| {
2496 let ident = &v.ident;
2497 quote_spanned! { ident.span() =>
2498 #i => Self::#ident,
2499 }
2500 });
2501 quote! {
2502 match tag.to_usize() {
2503 #(#from_tag)*
2504 _ => unreachable!(),
2505 }
2506 }
2507 }
2508 Data::Union(data) => {
2509 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2510 }
2511 }
2512}
2513
2514fn gen_kind(data: &Data) -> proc_macro2::TokenStream {
2515 match data {
2516 Data::Struct(data) => {
2517 Error::new_spanned(data.struct_token, "`struct`s are not supported").to_compile_error()
2518 }
2519 Data::Enum(data) => {
2520 if data.variants.is_empty() {
2521 return quote! {
2522 match *self {}
2523 };
2524 }
2525 let variants = data.variants.iter().map(|v| {
2526 let ident = &v.ident;
2527 quote_spanned! { ident.span() =>
2528 Self::#ident {..} => __Kind::#ident,
2529 }
2530 });
2531 quote! {
2532 match self {
2533 #(#variants)*
2534 }
2535 }
2536 }
2537 Data::Union(data) => {
2538 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2539 }
2540 }
2541}
2542
2543#[proc_macro_derive(MaybeHasNiche, attributes(niche))]
2556pub fn derive_maybe_has_niche(input: TokenStream) -> TokenStream {
2557 let input = parse_macro_input!(input as DeriveInput);
2558 let name = input.ident;
2559 let mn_array = gen_mn_array(&input.data, &input.attrs);
2560 let (_, ty_generics, _) = input.generics.split_for_impl();
2561 let generics = match bounds_maybe_has_niche(input.generics.clone(), &input.data, &input.attrs) {
2562 Ok(g) => g,
2563 Err(e) => return e.into_compile_error().into(),
2564 };
2565 let (impl_generics, _, where_clause) = generics.split_for_impl();
2566 let target = parse_for(&name, &input.attrs);
2567 let output = quote! {
2568 const _: () = {
2569 use ::object_rainbow::typenum::tarr;
2570
2571 #[automatically_derived]
2572 impl #impl_generics ::object_rainbow::MaybeHasNiche
2573 for #target #ty_generics #where_clause {
2574 type MnArray = #mn_array;
2575 }
2576 };
2577 };
2578 TokenStream::from(output)
2579}
2580
2581#[derive(Debug, FromMeta)]
2582#[darling(derive_syn_parse)]
2583struct ContainerNicheArgs {
2584 #[darling(default)]
2585 tag: bool,
2586}
2587
2588fn parse_niche_tag(attrs: &[Attribute]) -> syn::Result<bool> {
2589 let mut t = false;
2590 for attr in attrs {
2591 if attr_str(attr).as_deref() == Some("niche") {
2592 let ContainerNicheArgs { tag } = attr.parse_args()?;
2593 if tag {
2594 t = true;
2595 }
2596 }
2597 }
2598 Ok(t)
2599}
2600
2601fn bounds_maybe_has_niche(
2602 mut generics: Generics,
2603 data: &Data,
2604 attrs: &[Attribute],
2605) -> syn::Result<Generics> {
2606 let tag = parse_niche_tag(attrs)?;
2607 match data {
2608 Data::Struct(data) => {
2609 for f in data.fields.iter() {
2610 let ty = &f.ty;
2611 generics
2612 .make_where_clause()
2613 .predicates
2614 .push(parse_quote_spanned! { ty.span() =>
2615 #ty: ::object_rainbow::MaybeHasNiche<
2616 MnArray: ::object_rainbow::MnArray<
2617 MaybeNiche: ::object_rainbow::MaybeNiche
2618 >
2619 >
2620 });
2621 }
2622 }
2623 Data::Enum(data) => {
2624 if tag {
2625 return Ok(generics);
2626 }
2627 generics.params.push(parse_quote!(
2628 __N: ::object_rainbow::typenum::Unsigned
2629 ));
2630 for (i, v) in data.variants.iter().enumerate() {
2631 let mn_array = fields_mn_array(&v.fields, Some(i));
2632 generics
2633 .make_where_clause()
2634 .predicates
2635 .push(parse_quote_spanned! { v.span() =>
2636 #mn_array: ::object_rainbow::MnArray<
2637 MaybeNiche: ::object_rainbow::NicheOr<N = __N>
2638 >
2639 });
2640 for f in v.fields.iter() {
2641 let ty = &f.ty;
2642 generics.make_where_clause().predicates.push(
2643 parse_quote_spanned! { ty.span() =>
2644 #ty: ::object_rainbow::MaybeHasNiche<
2645 MnArray: ::object_rainbow::MnArray<
2646 MaybeNiche: ::object_rainbow::MaybeNiche
2647 >
2648 >
2649 },
2650 );
2651 }
2652 }
2653 }
2654 Data::Union(data) => {
2655 return Err(Error::new_spanned(
2656 data.union_token,
2657 "`union`s are not supported",
2658 ));
2659 }
2660 }
2661 Ok(generics)
2662}
2663
2664fn fields_mn_array(fields: &syn::Fields, variant: Option<usize>) -> proc_macro2::TokenStream {
2665 let mn_array = fields.iter().map(|f| {
2666 let ty = &f.ty;
2667 quote! {
2668 <
2669 <
2670 #ty
2671 as
2672 ::object_rainbow::MaybeHasNiche
2673 >::MnArray
2674 as
2675 ::object_rainbow::MnArray
2676 >::MaybeNiche
2677 }
2678 });
2679 if let Some(variant) = variant {
2680 let kind_niche = quote! {
2681 ::object_rainbow::AutoEnumNiche<Self, #variant>
2682 };
2683 quote! {
2684 tarr![
2685 #kind_niche,
2686 ::object_rainbow::NoNiche<::object_rainbow::HackNiche<#variant>>, #(#mn_array),*
2687 ]
2688 }
2689 } else {
2690 quote! { tarr![#(#mn_array),*] }
2691 }
2692}
2693
2694fn gen_mn_array(data: &Data, attrs: &[Attribute]) -> proc_macro2::TokenStream {
2695 let tag = match parse_niche_tag(attrs) {
2696 Ok(tag) => tag,
2697 Err(e) => return e.into_compile_error(),
2698 };
2699 match data {
2700 Data::Struct(data) => fields_mn_array(&data.fields, None),
2701 Data::Enum(data) => {
2702 if tag {
2703 return quote! {
2704 <
2705 <Self as ::object_rainbow::Enum>::Kind as ::object_rainbow::MaybeHasNiche
2706 >::MnArray
2707 };
2708 }
2709 let mn_array = data.variants.iter().enumerate().map(|(i, v)| {
2710 let mn_array = fields_mn_array(&v.fields, Some(i));
2711 quote! { <#mn_array as ::object_rainbow::MnArray>::MaybeNiche }
2712 });
2713 quote! {
2714 ::object_rainbow::NicheFoldOrArray<tarr![#(#mn_array),*]>
2715 }
2716 }
2717 Data::Union(data) => {
2718 Error::new_spanned(data.union_token, "`union`s are not supported").into_compile_error()
2719 }
2720 }
2721}
2722
2723#[proc_macro_derive(CanonicalExtra)]
2724pub fn derive_canonical_extra(input: TokenStream) -> TokenStream {
2725 let input = parse_macro_input!(input as DeriveInput);
2726 let name = input.ident;
2727 let generics = input.generics.clone();
2728 let (_, ty_generics, _) = generics.split_for_impl();
2729 let generics = match bounds_canonical_extra(input.generics, &input.data) {
2730 Ok(g) => g,
2731 Err(e) => return e.into_compile_error().into(),
2732 };
2733 let (impl_generics, _, where_clause) = generics.split_for_impl();
2734 let target = parse_for(&name, &input.attrs);
2735 let output = quote! {
2736 #[automatically_derived]
2737 impl #impl_generics ::object_rainbow::CanonicalExtra for #target #ty_generics #where_clause {
2738 type Extra = __Extra;
2739 }
2740 };
2741 TokenStream::from(output)
2742}
2743
2744#[proc_macro_derive(ToCanonicalExtra)]
2745pub fn derive_to_canonical_extra(input: TokenStream) -> TokenStream {
2746 let input = parse_macro_input!(input as DeriveInput);
2747 let name = input.ident;
2748 let generics = input.generics.clone();
2749 let (_, ty_generics, _) = generics.split_for_impl();
2750 let generics = match bounds_to_canonical_extra(input.generics, &input.data) {
2751 Ok(g) => g,
2752 Err(e) => return e.into_compile_error().into(),
2753 };
2754 let canonical_extra = gen_canonical_extra(&input.data);
2755 let (impl_generics, _, where_clause) = generics.split_for_impl();
2756 let target = parse_for(&name, &input.attrs);
2757 let output = quote! {
2758 #[automatically_derived]
2759 impl #impl_generics ::object_rainbow::ToCanonicalExtra for #target #ty_generics #where_clause {
2760 fn canonical_extra(&self) -> Self::Extra {
2761 #canonical_extra
2762 }
2763 }
2764 };
2765 TokenStream::from(output)
2766}
2767
2768fn bounds_canonical_extra(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
2769 match data {
2770 Data::Struct(data) => {
2771 if let Some(f) = data.fields.iter().next() {
2772 let ty = &f.ty;
2773 generics
2774 .make_where_clause()
2775 .predicates
2776 .push(parse_quote_spanned! { ty.span() =>
2777 #ty: ::object_rainbow::CanonicalExtra<Extra = __Extra>
2778 });
2779 }
2780 }
2781 Data::Enum(data) => {
2782 for variant in &data.variants {
2783 if let Some(f) = variant.fields.iter().next() {
2784 let ty = &f.ty;
2785 generics.make_where_clause().predicates.push(
2786 parse_quote_spanned! { ty.span() =>
2787 #ty: ::object_rainbow::CanonicalExtra<Extra = __Extra>
2788 },
2789 );
2790 }
2791 }
2792 }
2793 Data::Union(data) => {
2794 return Err(Error::new_spanned(
2795 data.union_token,
2796 "`union`s are not supported",
2797 ));
2798 }
2799 }
2800 generics.params.push(parse_quote!(__Extra));
2801 Ok(generics)
2802}
2803
2804fn bounds_to_canonical_extra(mut generics: Generics, data: &Data) -> syn::Result<Generics> {
2805 match data {
2806 Data::Struct(data) => {
2807 if let Some(f) = data.fields.iter().next() {
2808 let ty = &f.ty;
2809 generics
2810 .make_where_clause()
2811 .predicates
2812 .push(parse_quote_spanned! { ty.span() =>
2813 #ty: ::object_rainbow::ToCanonicalExtra<Extra = __Extra>
2814 });
2815 }
2816 }
2817 Data::Enum(data) => {
2818 for variant in &data.variants {
2819 if let Some(f) = variant.fields.iter().next() {
2820 let ty = &f.ty;
2821 generics.make_where_clause().predicates.push(
2822 parse_quote_spanned! { ty.span() =>
2823 #ty: ::object_rainbow::ToCanonicalExtra<Extra = __Extra>
2824 },
2825 );
2826 }
2827 }
2828 }
2829 Data::Union(data) => {
2830 return Err(Error::new_spanned(
2831 data.union_token,
2832 "`union`s are not supported",
2833 ));
2834 }
2835 }
2836 generics.params.push(parse_quote!(__Extra));
2837 Ok(generics)
2838}
2839
2840fn fields_canonical_extra(
2841 fields: &syn::Fields,
2842 unit_span: Option<Span>,
2843) -> proc_macro2::TokenStream {
2844 match fields {
2845 syn::Fields::Named(fields) => {
2846 if let Some(f) = fields.named.iter().next() {
2847 let ident = f.ident.as_ref().unwrap();
2848 quote! {
2849 { #ident, .. }
2850 => ::object_rainbow::ToCanonicalExtra::canonical_extra(#ident),
2851 }
2852 } else {
2853 let span = fields.brace_token.span.close();
2854 syn::Error::new(span, "no fields").into_compile_error()
2855 }
2856 }
2857 syn::Fields::Unnamed(fields) => {
2858 if !fields.unnamed.is_empty() {
2859 quote! {
2860 (__first, ..)
2861 => ::object_rainbow::ToCanonicalExtra::canonical_extra(__first),
2862 }
2863 } else {
2864 let span = fields.paren_token.span.close();
2865 syn::Error::new(span, "no fields").into_compile_error()
2866 }
2867 }
2868 syn::Fields::Unit => syn::Error::new(unit_span.unwrap(), "no fields").into_compile_error(),
2869 }
2870}
2871
2872fn gen_canonical_extra(data: &Data) -> proc_macro2::TokenStream {
2873 match data {
2874 Data::Struct(data) => {
2875 let arm = fields_canonical_extra(&data.fields, data.semi_token.map(|x| x.span));
2876 quote! {
2877 match self {
2878 Self #arm
2879 }
2880 }
2881 }
2882 Data::Enum(data) => {
2883 let arms = data.variants.iter().map(|variant| {
2884 let ident = &variant.ident;
2885 let arm = fields_canonical_extra(&variant.fields, Some(ident.span()));
2886 quote! {
2887 Self::#ident #arm
2888 }
2889 });
2890 quote! {
2891 match self {
2892 #(#arms)*
2893 }
2894 }
2895 }
2896 Data::Union(data) => {
2897 Error::new_spanned(data.union_token, "`union`s are not supported").to_compile_error()
2898 }
2899 }
2900}
2901
2902#[proc_macro_attribute]
2903pub fn derive_for_wrapped(args: TokenStream, input: TokenStream) -> TokenStream {
2904 let input = parse_macro_input!(input as ItemTrait);
2905 let sup = if args.is_empty() {
2906 let sup = input.supertraits.clone();
2907 quote!(#sup)
2908 } else {
2909 args.into()
2910 };
2911 let name = input.ident.clone();
2912 let generics = input.generics.clone();
2913 let (_, ty_generics, _) = generics.split_for_impl();
2914 let mut derived = Vec::new();
2915 for (path, extra) in [
2916 (
2917 quote!(map_extra::MappedExtra),
2918 vec![(quote!(__M), quote!(#sup))],
2919 ),
2920 (quote!(length_prefixed::Lp), vec![]),
2921 ] {
2922 let mut generics = input.generics.clone();
2923 generics.params.push(parse_quote! {
2924 __T: #name #ty_generics
2925 });
2926 for (i, ty) in &extra {
2927 generics.params.push(parse_quote! {
2928 #i: #ty
2929 });
2930 }
2931 let (impl_generics, _, where_clause) = generics.split_for_impl();
2932 let i = input
2933 .items
2934 .clone()
2935 .into_iter()
2936 .map(|i| match i {
2937 TraitItem::Const(i) => ImplItem::Const({
2938 let const_token = i.const_token;
2939 let ident = i.ident;
2940 let colon_token = i.colon_token;
2941 let ty = i.ty;
2942 let semi_token = i.semi_token;
2943 parse_quote! {
2944 #const_token
2945 #ident
2946 #colon_token
2947 #ty
2948 =
2949 <__T as #name #ty_generics>::#ident
2950 #semi_token
2951 }
2952 }),
2953 TraitItem::Fn(i) => ImplItem::Fn({
2954 let mut sig = i.sig;
2955 let ident = sig.ident.clone();
2956 let args = sig
2957 .inputs
2958 .iter_mut()
2959 .enumerate()
2960 .map(|(n, i)| match i {
2961 FnArg::Receiver(receiver) => {
2962 let reference = receiver.reference.as_ref().map(|(and, _)| and);
2963 let mutability = receiver.mutability.as_ref();
2964 let ident = &receiver.self_token;
2965 quote!(#reference #mutability *#ident)
2966 }
2967 FnArg::Typed(pat_type) => {
2968 let ident = Ident::new(&format!("arg{n}"), pat_type.span());
2969 *pat_type.pat = parse_quote!(#ident);
2970 quote!(#ident)
2971 }
2972 })
2973 .collect::<Vec<_>>();
2974 parse_quote! {
2975 #sig
2976 {
2977 <__T as #name #ty_generics>::#ident(
2978 #(#args),*
2979 )
2980 }
2981 }
2982 }),
2983 TraitItem::Type(i) => ImplItem::Type({
2984 let type_token = i.type_token;
2985 let ident = i.ident;
2986 let semi_token = i.semi_token;
2987 parse_quote! {
2988 #type_token
2989 #ident
2990 =
2991 <__T as #name #ty_generics>::#ident
2992 #semi_token
2993 }
2994 }),
2995 _ => unimplemented!("unknown/unsupported item"),
2996 })
2997 .collect::<Vec<_>>();
2998 let extra = extra.into_iter().map(|(k, _)| k);
2999 derived.push(quote! {
3000 #[automatically_derived]
3001 impl #impl_generics #name #ty_generics for ::object_rainbow::#path<
3002 __T,
3003 #(#extra),*
3004 >
3005 #where_clause
3006 {
3007 #(#i)*
3008 }
3009 });
3010 }
3011 let output = quote! {
3012 #input
3013
3014 #(#derived)*
3015 };
3016 output.into()
3017}
3018
3019#[derive(Debug, FromMeta, Default)]
3020#[darling(derive_syn_parse)]
3021struct PodArgs {
3022 #[darling(default)]
3023 no_clone: SpannedValue<bool>,
3024 #[darling(default)]
3025 no_copy: SpannedValue<bool>,
3026 #[darling(default)]
3027 no_default: SpannedValue<bool>,
3028 #[darling(default)]
3029 no_size: SpannedValue<bool>,
3030 #[darling(default)]
3031 no_niche: SpannedValue<bool>,
3032 #[darling(default)]
3033 no_output: SpannedValue<bool>,
3034 #[darling(default)]
3035 no_tagged: SpannedValue<bool>,
3036 #[darling(default)]
3037 no_parse: SpannedValue<bool>,
3038 #[darling(default)]
3039 no_inline: SpannedValue<bool>,
3040 #[darling(default)]
3041 no_inline_output: SpannedValue<bool>,
3042 #[darling(default)]
3043 no_byte_ord: SpannedValue<bool>,
3044}
3045
3046#[proc_macro_attribute]
3047pub fn pod(args: TokenStream, input: TokenStream) -> TokenStream {
3048 let (
3049 PodArgs {
3050 no_clone,
3051 no_copy,
3052 no_default,
3053 no_size,
3054 no_niche,
3055 no_output,
3056 no_tagged,
3057 no_parse,
3058 no_inline,
3059 no_inline_output,
3060 no_byte_ord,
3061 },
3062 args_error,
3063 ) = match syn::parse(args) {
3064 Ok(args) => (args, Default::default()),
3065 Err(e) => (Default::default(), e.into_compile_error()),
3066 };
3067 let thing = proc_macro2::TokenStream::from(input);
3068 let derive_enum = match syn::parse2::<Item>(thing.clone()) {
3069 Ok(Item::Struct(_)) => Ok(quote! {}),
3070 Ok(Item::Enum(_)) => Ok(quote! {
3071 ::object_rainbow::Enum,
3072 }),
3073 Ok(_) => Err(syn::Error::new(thing.span(), "not `struct` or `enum`")),
3074 Err(e) => Err(e),
3075 }
3076 .unwrap_or_else(|e| e.into_compile_error());
3077 let yes_clone = !no_clone.into_inner();
3078 let yes_copy = !no_copy.into_inner();
3079 let derive_clone = if yes_clone {
3080 quote! {
3081 ::core::clone::Clone,
3082 }
3083 } else {
3084 quote! {}
3085 };
3086 let derive_copy = if yes_clone && yes_copy {
3087 quote! {
3088 ::core::marker::Copy,
3089 }
3090 } else {
3091 quote! {}
3092 };
3093 let derive_default = if no_default.into_inner() {
3094 quote! {}
3095 } else {
3096 quote! {
3097 ::core::default::Default,
3098 }
3099 };
3100 let derive_tagged = if no_tagged.into_inner() {
3101 quote! {}
3102 } else {
3103 quote! {
3104 ::object_rainbow::Tagged,
3105 }
3106 };
3107 let yes_output = !no_output.into_inner();
3108 let yes_parse = !no_parse.into_inner();
3109 let yes_inline = !no_inline.into_inner();
3110 let yes_inline_output = !no_inline_output.into_inner();
3111 let yes_byte_ord = !no_byte_ord.into_inner();
3112 let yes_size = !no_size.into_inner();
3113 let yes_niche = !no_niche.into_inner();
3114 let derive_to_output = if yes_output {
3115 quote! {
3116 ::object_rainbow::ToOutput,
3117 }
3118 } else {
3119 quote! {}
3120 };
3121 let derive_inline_output = if yes_output && yes_inline && yes_inline_output {
3122 quote! {
3123 ::object_rainbow::InlineOutput,
3124 }
3125 } else {
3126 quote! {}
3127 };
3128 let derive_byte_ord = if yes_output && yes_byte_ord {
3129 quote! {
3130 ::object_rainbow::ByteOrd,
3131 }
3132 } else {
3133 quote! {}
3134 };
3135 let derive_parse = if yes_parse {
3136 quote! {
3137 ::object_rainbow::Parse,
3138 }
3139 } else {
3140 quote! {}
3141 };
3142 let derive_parse_inline = if yes_parse && yes_inline {
3143 quote! {
3144 ::object_rainbow::ParseInline,
3145 }
3146 } else {
3147 quote! {}
3148 };
3149 let derive_size = if yes_size && yes_output {
3150 quote! {
3151 ::object_rainbow::Size,
3152 }
3153 } else {
3154 quote! {}
3155 };
3156 let derive_niche = if yes_niche && yes_output {
3157 quote! {
3158 ::object_rainbow::MaybeHasNiche,
3159 }
3160 } else {
3161 quote! {}
3162 };
3163 let thing = quote! {
3164 #args_error
3165 #[derive(
3166 #derive_enum
3167 #derive_clone
3168 #derive_copy
3169 ::core::cmp::PartialEq,
3170 ::core::cmp::Eq,
3171 ::core::cmp::PartialOrd,
3172 ::core::cmp::Ord,
3173 #derive_default
3174 ::core::fmt::Debug,
3175 ::core::hash::Hash,
3176 #derive_to_output
3177 #derive_inline_output
3178 #derive_byte_ord
3179 #derive_tagged
3180 ::object_rainbow::ListHashes,
3181 ::object_rainbow::Topological,
3182 #derive_parse
3183 #derive_parse_inline
3184 #derive_size
3185 #derive_niche
3186 )]
3187 #thing
3188 };
3189 thing.into()
3190}