1#[cfg(test)]
4mod tests;
5
6mod pretty;
7
8mod errors;
9mod options;
10
11use std::collections::HashMap;
12
13use core::ops::Not;
14use errors::tri;
15use options::AttrOptions;
16use proc_macro2::{Span, TokenStream};
17use quote::{quote, ToTokens};
18use syn::{fold::Fold, parse_quote};
19
20#[proc_macro_attribute]
21pub fn tag(
22 attr: proc_macro::TokenStream,
23 item: proc_macro::TokenStream,
24) -> proc_macro::TokenStream {
25 tag_impl(attr.into(), item.into()).into()
26}
27
28fn tag_impl(attr: TokenStream, item: TokenStream) -> TokenStream {
29 let options = tri!(syn::parse2::<AttrOptions>(attr));
30 let alias = tri!(syn::parse2::<syn::ItemType>(item));
31
32 let options: Options = tri!(options.try_into());
33
34 let attributes = tri!(Attributes::new(&alias.attrs));
35
36 let generics = tri!(Generics::new(&alias.generics.params));
37
38 let struct_def = StructDef::new(&alias, &attributes, &generics);
39
40 let tags_tag_impl = TagsTagImpl::new(&alias, &attributes, &generics);
41
42 let tag_impl = TagImpl::new(&alias, &attributes, &generics);
43
44 let with_lt_impl = WithLtImpl::new(&alias, &attributes, &generics);
45
46 let local_impl = if !options.remote {
47 Some(TagsTyImpl::new(&alias, &attributes, &generics, None))
48 } else {
49 None
50 };
51
52 let local_groups = options
53 .local_groups
54 .iter()
55 .map(|group| TagsTyImpl::new(&alias, &attributes, &generics, Some(group)))
56 .collect::<Vec<_>>();
57
58 quote! {
59 #struct_def
60
61 #local_impl
62
63 #(#local_groups)*
64
65 #tags_tag_impl
66
67 #tag_impl
68
69 #with_lt_impl
70 }
71}
72
73struct Options {
74 remote: bool,
75 local_groups: Vec<syn::Type>,
76}
77
78impl TryFrom<AttrOptions> for Options {
79 type Error = syn::Error;
80
81 fn try_from(value: AttrOptions) -> Result<Self, Self::Error> {
82 let mut remote = false;
83 let mut local_groups = Vec::new();
84
85 for option in value.options {
86 match &*option.name {
87 "remote" => {
88 remote = true;
89 }
90 "group" => {
91 let Some(value) = option.value else {
92 return Err(syn::Error::new(Span::call_site(), "missing type of group"));
93 };
94
95 local_groups.push(syn::parse2(value)?);
96 }
97 _ => {
98 return Err(syn::Error::new(
99 Span::call_site(),
100 format!("unknown option `{}`", option.name),
101 ))
102 }
103 }
104 }
105
106 Ok(Self {
107 remote,
108 local_groups,
109 })
110 }
111}
112
113struct TyTagPath;
114
115impl ToTokens for TyTagPath {
116 fn to_tokens(&self, tokens: &mut TokenStream) {
117 tokens.extend(quote! { ::ty_tag });
118 }
119}
120
121const CRATE: TyTagPath = TyTagPath;
122
123struct StructDef<'a> {
124 attributes: &'a Attributes<'a>,
125 custom_doc: Option<String>,
126 vis: &'a syn::Visibility,
127 name: &'a syn::Ident,
128 generics: &'a Generics<'a>,
129}
130
131impl<'a> StructDef<'a> {
132 fn new(
133 alias: &'a syn::ItemType,
134 attributes: &'a Attributes<'a>,
135 generics: &'a Generics<'a>,
136 ) -> Self {
137 let custom_doc = attributes.docs.is_empty().then(|| {
138 if let Some(link) = JustTypePath::strip_type(&alias.ty) {
139 format!(
140 "Tag for type [`{0}`]({1}).",
141 pretty::unparse_type(&alias.ty),
142 pretty::unparse_type(&link),
143 )
144 } else {
145 format!("Tag for type `{0}`.", pretty::unparse_type(&alias.ty))
146 }
147 });
148
149 Self {
150 attributes,
151 custom_doc,
152 vis: &alias.vis,
153 name: &alias.ident,
154 generics,
155 }
156 }
157}
158
159impl ToTokens for StructDef<'_> {
160 fn to_tokens(&self, tokens: &mut TokenStream) {
161 let Self {
162 attributes,
163 custom_doc,
164 vis,
165 name,
166 generics,
167 } = &self;
168
169 let generic_type_holder = generics
173 .types_is_empty()
174 .not()
175 .then(|| {
176 let type_generics =
177 generics.with_types(|TypeGeneric { ident, .. }| quote! { *const #ident });
178
179 quote! { , ::core::marker::PhantomData<fn() -> (#(#type_generics,)*)> }
180 })
181 .unwrap_or_default();
182
183 let generics_def = generics
186 .types_and_consts_is_empty()
187 .not()
188 .then(|| {
189 let generics = generics.with_types_and_consts(
190 |TypeGeneric { ident, default, .. }| {
191 let default = default.iter();
192
193 quote! { #ident: ?Sized #(= #default)* }
194 },
195 |ConstGeneric { ident, ty, default }| {
196 let default = default.iter();
197
198 quote! { const #ident: #ty #(= #default)* }
199 },
200 );
201
202 quote! { <#(#generics),*> }
203 })
204 .unwrap_or_default();
205
206 let custom_doc = custom_doc.as_ref().map(|doc| {
207 quote! { #[doc = #doc] }
208 });
209
210 let attrs = &attributes.struct_attrs;
211 let docs = &attributes.docs;
212
213 tokens.extend(quote! {
216 #(#docs)*
217 #custom_doc
218 #(#attrs)*
219 #vis struct #name #generics_def(#CRATE::__ #generic_type_holder);
220 });
221 }
222}
223
224struct TagsTyImpl<'a> {
225 attributes: &'a Attributes<'a>,
226 tag_type: TagType<'a>,
227 ty: &'a syn::Type,
228 generics: &'a Generics<'a>,
229 group: Option<&'a syn::Type>,
230}
231
232impl<'a> TagsTyImpl<'a> {
233 fn new(
234 alias: &'a syn::ItemType,
235 attributes: &'a Attributes<'a>,
236 generics: &'a Generics,
237 group: Option<&'a syn::Type>,
238 ) -> Self {
239 Self {
240 attributes,
241 tag_type: TagType::new(&alias.ident, generics),
242 generics,
243 ty: &alias.ty,
244 group,
245 }
246 }
247}
248
249impl ToTokens for TagsTyImpl<'_> {
250 fn to_tokens(&self, tokens: &mut TokenStream) {
251 let Self {
252 attributes,
253 tag_type,
254 generics,
255 ty,
256 group,
257 } = &self;
258
259 let krate = CRATE;
260
261 let lt_generics = generics.with_lifetimes(|LifetimeGeneric { lifetime, bounds }| {
262 if bounds.is_empty() {
263 lifetime.into_token_stream()
264 } else {
265 quote! { #lifetime: #(#bounds)+* }
266 }
267 });
268
269 let types_and_consts_generics = generics.with_types_and_consts(
270 |TypeGeneric {
271 ident,
272 bounds,
273 is_itself,
274 ..
275 }| {
276 if *is_itself {
277 quote! {
278 #ident: #(#bounds)+*
279 }
280 } else {
281 quote! {
282 #ident: #(#bounds + )* ::ty_tag::Tagged<__Group>
283 }
284 }
285 },
286 |ConstGeneric { ident, ty, .. }| quote! { const #ident: #ty },
287 );
288
289 let generics_def = if generics.is_empty() {
290 if group.is_some() {
291 TokenStream::new()
292 } else {
293 quote! { <__Group: ?Sized> }
294 }
295 } else if group.is_none() {
296 quote! { <#(#lt_generics,)* __Group: ?Sized #(, #types_and_consts_generics)*> }
297 } else {
298 quote! { <#(#lt_generics,)* #( #types_and_consts_generics),*> }
299 };
300
301 let group = if let Some(group) = group {
302 group.into_token_stream()
303 } else {
304 quote! { __Group }
305 };
306
307 let mut replacement = GenericTypeReplace {
308 replacements: generics
309 .with_types(|ty| ty)
310 .filter(|ty| !ty.is_itself)
311 .map(|TypeGeneric { ident, .. }| {
312 (
313 *ident,
314 parse_quote! {
315 <#ident as #krate::Tagged<#group>>::Tag
316 },
317 )
318 })
319 .collect(),
320 };
321
322 let tag_type_tag = replacement.fold_type(parse_quote! { #tag_type });
323
324 let where_clause = if generics
325 .with_types(|ty| !ty.is_itself)
326 .filter(|x| *x)
327 .count()
328 <= 1
329 {
330 TokenStream::new()
331 } else {
332 let type_generics = generics.with_types(|ty| ty).flat_map(
333 |TypeGeneric {
334 ident, is_itself, ..
335 }| {
336 if *is_itself {
337 None
338 } else {
339 Some(quote! {
340 <
341 <#ident as #krate::Tagged<#group>>::Tag
342 as #krate::Tag>::NeededLifetimes,
343 })
344 }
345 },
346 );
347
348 quote! {
349 where
350 (#(#type_generics)*): ::ty_tag::lifetime_list::ops::Longest<
351 Output: ::ty_tag::lifetime_list::HoleList
352 >
353 }
354 };
355
356 let attrs = &attributes.impl_attrs;
357
358 tokens.extend(quote! {
359 #(#attrs)*
360 impl #generics_def #CRATE::Tagged<#group> for #ty
361 #where_clause
362 {
363 type Tag = #tag_type_tag;
364 }
365 });
366 }
367}
368
369struct TagsTagImpl<'a> {
370 attributes: &'a Attributes<'a>,
371 generics: &'a Generics<'a>,
372 tag_type: TagType<'a>,
373}
374
375impl<'a> TagsTagImpl<'a> {
376 fn new(
377 alias: &'a syn::ItemType,
378 attributes: &'a Attributes<'a>,
379 generics: &'a Generics,
380 ) -> Self {
381 let tag_type = TagType::new(&alias.ident, generics);
382
383 Self {
384 tag_type,
385 generics,
386 attributes,
387 }
388 }
389}
390
391impl ToTokens for TagsTagImpl<'_> {
392 fn to_tokens(&self, tokens: &mut TokenStream) {
393 let Self {
394 tag_type,
395 generics,
396 attributes,
397 } = &self;
398
399 let krate = CRATE;
400
401 let generics_def = if generics.types_and_consts_is_empty() {
402 quote! { <__Group: ?Sized> }
403 } else {
404 let generics = generics.with_types_and_consts(
405 |TypeGeneric {
406 ident,
407 bounds,
408 is_itself,
409 ..
410 }| {
411 if *is_itself {
412 quote! { #ident: #(#bounds)+* }
413 } else {
414 quote! { #ident: ?Sized + ::ty_tag::Tagged<__Group> }
415 }
416 },
417 |ConstGeneric { ident, ty, .. }| quote! { const #ident: #ty },
418 );
419
420 quote! { <__Group: ?Sized #(, #generics)*> }
421 };
422
423 let mut replacement = GenericTypeReplace {
424 replacements: generics
425 .with_types(|ty| ty)
426 .filter(|ty| !ty.is_itself)
427 .map(|TypeGeneric { ident, .. }| {
428 (
429 *ident,
430 parse_quote! {
431 <#ident as #krate::Tagged<__Group>>::Tag
432 },
433 )
434 })
435 .collect(),
436 };
437
438 let tag_type_tag = replacement.fold_type(parse_quote! { #tag_type });
439
440 let where_clause = if generics
441 .with_types(|ty| !ty.is_itself)
442 .filter(|x| *x)
443 .count()
444 <= 1
445 {
446 TokenStream::new()
447 } else {
448 let type_generics = generics.with_types(|ty| ty).flat_map(
449 |TypeGeneric {
450 ident, is_itself, ..
451 }| {
452 if *is_itself {
453 None
454 } else {
455 Some(quote! {
456 <
457 <#ident as #krate::Tagged<__Group>>::Tag
458 as #krate::Tag>::NeededLifetimes,
459 })
460 }
461 },
462 );
463
464 quote! {
465 where
466 (#(#type_generics)*): ::ty_tag::lifetime_list::ops::Longest<
467 Output: ::ty_tag::lifetime_list::HoleList
468 >
469 }
470 };
471
472 let attrs = &attributes.impl_attrs;
473
474 tokens.extend(quote! {
475 #(#attrs)*
476 impl #generics_def #CRATE::Tagged<__Group> for #tag_type
477 #where_clause
478 {
479 type Tag = #tag_type_tag;
480 }
481 });
482 }
483}
484
485struct TagImpl<'a> {
486 attributes: &'a Attributes<'a>,
487 hole_count: usize,
488 generics: &'a Generics<'a>,
489 tag_type: TagType<'a>,
490}
491
492impl<'a> TagImpl<'a> {
493 fn new(
494 alias: &'a syn::ItemType,
495 attributes: &'a Attributes<'a>,
496 generics: &'a Generics,
497 ) -> Self {
498 let tag_type = TagType::new(&alias.ident, generics);
499
500 Self {
501 attributes,
502 hole_count: alias.generics.lifetimes().count(),
503 generics,
504 tag_type,
505 }
506 }
507}
508
509impl ToTokens for TagImpl<'_> {
510 fn to_tokens(&self, tokens: &mut TokenStream) {
511 let Self {
512 hole_count,
513 generics,
514 tag_type,
515 attributes,
516 } = &self;
517
518 let holes = if *hole_count != 0 {
519 let tail = if generics
520 .with_types(|ty| !ty.is_itself)
521 .filter(|x| *x)
522 .count()
523 == 1
524 {
525 let type_generics = generics.with_types(|ty| &ty.ident);
526
527 Some(quote! { <#(#type_generics)* as #CRATE::Tag>::NeededLifetimes })
528 } else if generics
529 .with_types(|ty| !ty.is_itself)
530 .filter(|x| *x)
531 .count()
532 == 0
533 {
534 None
535 } else {
536 let type_generics = generics.with_types(|ty| ty).flat_map(
537 |TypeGeneric {
538 ident, is_itself, ..
539 }| if *is_itself { None } else { Some(ident) },
540 );
541
542 Some(quote! {
543 <(#(
544 <#type_generics as ::ty_tag::Tag>::NeededLifetimes,
545 )*) as ::ty_tag::lifetime_list::ops::Longest>::Output
546 })
547 };
548
549 let holes = HoleList {
550 count: *hole_count,
551 tail,
552 };
553 quote! { #holes }
554 } else if generics
555 .with_types(|ty| !ty.is_itself)
556 .filter(|x| *x)
557 .count()
558 == 0
559 {
560 let holes = HoleList {
561 count: 0,
562 tail: None,
563 };
564 quote! { #holes }
565 } else if generics
566 .with_types(|ty| !ty.is_itself)
567 .filter(|x| *x)
568 .count()
569 == 1
570 {
571 let type_generics = generics.with_types(|ty| ty).flat_map(
572 |TypeGeneric {
573 ident, is_itself, ..
574 }| if *is_itself { None } else { Some(ident) },
575 );
576
577 quote! { <#(#type_generics)* as #CRATE::Tag>::NeededLifetimes }
578 } else {
579 let type_generics = generics.with_types(|ty| ty).flat_map(
580 |TypeGeneric {
581 ident, is_itself, ..
582 }| if *is_itself { None } else { Some(ident) },
583 );
584
585 quote! {
586 <(#(
587 <#type_generics as ::ty_tag::Tag>::NeededLifetimes,
588 )*) as ::ty_tag::lifetime_list::ops::Longest>::Output
589 }
590 };
591
592 let krate = CRATE;
593
594 let where_clause = if generics
595 .with_types(|ty| !ty.is_itself)
596 .filter(|x| *x)
597 .count()
598 <= 1
599 {
600 TokenStream::new()
601 } else {
602 let type_generics = generics.with_types(|ty| ty).flat_map(
603 |TypeGeneric {
604 ident, is_itself, ..
605 }| {
606 if *is_itself {
607 None
608 } else {
609 Some(quote! {
610 <#ident as #krate::Tag>::NeededLifetimes,
611 })
612 }
613 },
614 );
615
616 quote! {
617 where
618 (#(#type_generics)*): ::ty_tag::lifetime_list::ops::Longest<
619 Output: ::ty_tag::lifetime_list::HoleList
620 >
621 }
622 };
623
624 let generics_def = if generics.is_empty() {
625 TokenStream::new()
626 } else {
627 let generics = generics.with_types_and_consts(
628 |TypeGeneric {
629 ident,
630 bounds,
631 is_itself,
632 ..
633 }| {
634 if *is_itself {
635 quote! {
636 #ident: #(#bounds)+*
637 }
638 } else {
639 quote! {
640 #ident: ?Sized + ::ty_tag::Tag
641 }
642 }
643 },
644 |ConstGeneric { ident, ty, .. }| quote! { const #ident: #ty },
645 );
646
647 quote! { <#(#generics),*> }
648 };
649
650 let attrs = &attributes.impl_attrs;
651
652 tokens.extend(quote! {
653 #(#attrs)*
654 impl #generics_def #CRATE::Tag for #tag_type
655 #where_clause
656 {
657 type NeededLifetimes = #holes;
658 }
659 });
660 }
661}
662
663struct WithLtImpl<'a> {
664 attributes: &'a Attributes<'a>,
665 ty: syn::Type,
666 sized_bounds: Vec<syn::Ident>,
667 where_bounds: Vec<syn::WherePredicate>,
668 tag_type: TagType<'a>,
669 generics: &'a Generics<'a>,
670}
671
672impl<'a> WithLtImpl<'a> {
673 fn new(
674 alias: &'a syn::ItemType,
675 attributes: &'a Attributes<'a>,
676 generics: &'a Generics,
677 ) -> Self {
678 let mut sized_bounds = HashMap::new();
679 let mut where_bounds = Vec::new();
680
681 for generic in generics.with_types(|ty| ty) {
682 if generic.is_itself {
683 continue
684 }
685
686 let bound = syn::WherePredicate::Type(syn::PredicateType {
687 lifetimes: None,
688 bounded_ty: syn::Type::Path(syn::TypePath {
689 qself: None,
690 path: syn::Path {
691 leading_colon: None,
692 segments: [syn::PathSegment {
693 ident: generic.ident.clone(),
694 arguments: syn::PathArguments::None,
695 }]
696 .into_iter()
697 .collect(),
698 },
699 }),
700 colon_token: Default::default(),
701 bounds: generic.bounds.iter().map(|x| (**x).clone()).collect(),
702 });
703
704 let sized = sized_bounds
705 .entry(generic.ident.clone())
706 .or_insert(FindAndRemoveSized { sized: None });
707
708 let bound = sized.fold_where_predicate(bound);
709
710 where_bounds.push(bound);
711 }
712
713 if let Some(clause) = &alias.generics.where_clause {
714 for predicate in &clause.predicates {
715 match predicate {
716 syn::WherePredicate::Type(predicate_type) => {
717 let bound = match &predicate_type.bounded_ty {
718 syn::Type::Path(type_path) => {
719 if let Some(ident) = type_path.path.get_ident() {
720 if let Some(sized) = sized_bounds.get_mut(ident) {
721 sized.fold_where_predicate(predicate.clone())
722 } else {
723 predicate.clone()
724 }
725 } else {
726 predicate.clone()
727 }
728 }
729 _ => predicate.clone(),
730 };
731 where_bounds.push(bound);
732 }
733 _ => where_bounds.push(predicate.clone()),
734 }
735 }
736 }
737
738 let mut replacement = GenericTypeReplace {
739 replacements: generics
740 .with_types(|ty| ty)
741 .filter(|ty| !ty.is_itself)
742 .map(|TypeGeneric { ident, .. }| {
743 (
744 *ident,
745 parse_quote! {
746 <#ident as #CRATE::WithLt<__L>>::Reified
747 },
748 )
749 })
750 .collect(),
751 };
752
753 for bound in &mut where_bounds {
754 *bound = replacement.fold_where_predicate(bound.clone());
755 }
756
757 if generics
758 .with_types(|ty| ty)
759 .filter(|ty| !ty.is_itself)
760 .count()
761 >= 2
762 {
763 let krate = CRATE;
764
765 let type_generics = generics.with_types(|ty| ty).filter(|ty| !ty.is_itself).map(
766 |TypeGeneric { ident, .. }| {
767 quote! {
768 <#ident as #krate::Tag>::NeededLifetimes,
769 }
770 },
771 );
772
773 where_bounds.push(parse_quote! {
774 (#(#type_generics)*): ::ty_tag::lifetime_list::ops::Longest<
775 Output: ::ty_tag::lifetime_list::HoleList
776 >
777 });
778 }
779
780 where_bounds.retain(|bound| match bound {
781 syn::WherePredicate::Type(predicate_type) => !predicate_type.bounds.is_empty(),
782 _ => true,
783 });
784
785 let tag_type = TagType::new(&alias.ident, generics);
786
787 let mut sized_bounds = sized_bounds
788 .into_iter()
789 .flat_map(|(ident, find)| {
790 if matches!(find.sized, Some(true) | None) {
791 Some(ident)
792 } else {
793 None
794 }
795 })
796 .collect::<Vec<_>>();
797
798 sized_bounds.sort();
799
800 Self {
801 ty: (*alias.ty).clone(),
802 generics,
803 tag_type,
804 where_bounds,
805 sized_bounds,
806 attributes,
807 }
808 }
809}
810
811impl ToTokens for WithLtImpl<'_> {
812 fn to_tokens(&self, tokens: &mut TokenStream) {
813 let Self {
814 ty,
815 generics,
816 sized_bounds,
817 where_bounds,
818 tag_type,
819 attributes,
820 } = self;
821
822 let krate = CRATE;
823
824 let generics_def = if generics.lifetimes_is_empty() {
825 if generics.is_empty() {
826 TokenStream::new()
827 } else if generics.with_types(|ty| ty).filter(|ty| !ty.is_itself).count() == 0 {
828 let generics = generics.with(
829 |LifetimeGeneric { lifetime, bounds }| {
830 if bounds.is_empty() {
831 lifetime.into_token_stream()
832 } else {
833 quote! { #lifetime: #(#bounds)+* }
834 }
835 },
836 |TypeGeneric {
837 ident,
838 bounds,
839 is_itself,
840 ..
841 }| {
842 if *is_itself {
843 quote! {
844 #ident: #(#bounds)+*
845 }
846 } else {
847 quote! {
848 #ident: ?Sized + ::ty_tag::WithLt<__L>
849 }
850 }
851 },
852 |ConstGeneric { ident, ty, .. }| quote! { const #ident: #ty },
853 );
854
855 quote! {
856 <#(#generics),*>
857 }
858 } else {
859 let generics = generics.with(
860 |LifetimeGeneric { lifetime, bounds }| {
861 if bounds.is_empty() {
862 lifetime.into_token_stream()
863 } else {
864 quote! { #lifetime: #(#bounds)+* }
865 }
866 },
867 |TypeGeneric {
868 ident,
869 bounds,
870 is_itself,
871 ..
872 }| {
873 if *is_itself {
874 quote! {
875 #ident: #(#bounds)+*
876 }
877 } else {
878 quote! {
879 #ident: ?Sized + ::ty_tag::WithLt<__L>
880 }
881 }
882 },
883 |ConstGeneric { ident, ty, .. }| quote! { const #ident: #ty },
884 );
885
886 quote! {
887 <
888 __L: #krate::lifetime_list::LifetimeList,
889 #(#generics),*
890 >
891 }
892 }
893 } else if generics.is_empty() {
894 let lt_generics = generics.with_lifetimes(|LifetimeGeneric { lifetime, bounds }| {
895 if bounds.is_empty() {
896 lifetime.into_token_stream()
897 } else {
898 quote! { #lifetime: #(#bounds)+* }
899 }
900 });
901
902 quote! { <#(#lt_generics),*> }
903 } else if generics.with_types(|ty| ty).filter(|ty| !ty.is_itself).count() == 0 {
904 let generics = generics.with(
905 |LifetimeGeneric { lifetime, bounds }| {
906 if bounds.is_empty() {
907 lifetime.into_token_stream()
908 } else {
909 quote! { #lifetime: #(#bounds)+* }
910 }
911 },
912 |TypeGeneric {
913 ident,
914 bounds,
915 is_itself,
916 ..
917 }| {
918 if *is_itself {
919 quote! {
920 #ident: #(#bounds)+*
921 }
922 } else {
923 quote! {
924 #ident: ?Sized + ::ty_tag::WithLt<__L>
925 }
926 }
927 },
928 |ConstGeneric { ident, ty, .. }| quote! { const #ident: #ty },
929 );
930
931 quote! {
932 <#(#generics),*>
933 }
934 } else {
935 let lt_generics = generics.with_lifetimes(|LifetimeGeneric { lifetime, bounds }| {
936 if bounds.is_empty() {
937 lifetime.into_token_stream()
938 } else {
939 quote! { #lifetime: #(#bounds)+* }
940 }
941 });
942
943 let generics = generics.with_types_and_consts(
944 |TypeGeneric {
945 ident,
946 bounds,
947 is_itself,
948 ..
949 }| {
950 if *is_itself {
951 quote! {
952 #ident: #(#bounds)+*
953 }
954 } else {
955 quote! {
956 #ident: ?Sized + ::ty_tag::WithLt<__L>
957 }
958 }
959 },
960 |ConstGeneric { ident, ty, .. }| quote! { const #ident: #ty },
961 );
962
963 quote! {
964 <
965 #(#lt_generics,)*
966 __L: #krate::lifetime_list::LifetimeList,
967 #(#generics),*
968 >
969 }
970 };
971
972 let where_clause = match (where_bounds.is_empty(), sized_bounds.is_empty()) {
973 (true, true) => TokenStream::new(),
974 (true, false) => {
975 let sized_bounds = sized_bounds.iter().collect::<Vec<_>>();
976
977 quote! {
978 where
979 #(<#sized_bounds as #krate::WithLt<__L>>::Reified: Sized),*
980 }
981 }
982 (false, true) => {
983 quote! {
984 where
985 #(#where_bounds),*
986 }
987 }
988 (false, false) => {
989 let sized_bounds = sized_bounds.iter().collect::<Vec<_>>();
990
991 quote! {
992 where
993 #(<#sized_bounds as #krate::WithLt<__L>>::Reified: Sized,)*
994 #(#where_bounds),*
995 }
996 }
997 };
998
999 let l = if generics.with_types(|ty| ty).filter(|ty| !ty.is_itself).count() == 0 {
1000 let lifetimes = generics
1001 .with_lifetimes(|l| l.lifetime.clone())
1002 .collect::<Vec<_>>();
1003
1004 let l = LifetimeList {
1005 lifetimes: &lifetimes,
1006 tail: None,
1007 };
1008
1009 quote! { #l }
1010 } else if generics.lifetimes_is_empty() {
1011 quote! { __L }
1012 } else {
1013 let lifetimes = generics
1014 .with_lifetimes(|l| l.lifetime.clone())
1015 .collect::<Vec<_>>();
1016
1017 let l = LifetimeList {
1018 lifetimes: &lifetimes,
1019 tail: Some(quote! { __L }),
1020 };
1021 quote! { #l }
1022 };
1023
1024 let mut replacement = GenericTypeReplace {
1025 replacements: generics
1026 .with_types(|ty| ty)
1027 .filter(|ty| !ty.is_itself)
1028 .map(|TypeGeneric { ident, .. }| {
1029 (
1030 *ident,
1031 parse_quote! {
1032 <#ident as #CRATE::WithLt<__L>>::Reified
1033 },
1034 )
1035 })
1036 .collect(),
1037 };
1038
1039 let reified_ty = replacement.fold_type(ty.clone());
1040
1041 let attrs = &attributes.impl_attrs;
1042
1043 tokens.extend(quote! {
1044 #(#attrs)*
1045 impl #generics_def #CRATE::WithLt<#l> for #tag_type
1046 #where_clause
1047 {
1048 type Reified = #reified_ty;
1049 }
1050 });
1051 }
1052}
1053
1054struct LifetimeList<'a> {
1055 lifetimes: &'a [syn::Lifetime],
1056 tail: Option<TokenStream>,
1057}
1058
1059impl ToTokens for LifetimeList<'_> {
1060 fn to_tokens(&self, tokens: &mut TokenStream) {
1061 let mut iter = self.lifetimes.iter();
1062
1063 if let Some(lt) = iter.next() {
1064 tokens.extend(
1065 quote! { #CRATE::lifetime_list::cons::Cons<#CRATE::lifetime_list::Inv<#lt> },
1066 );
1067 } else {
1068 tokens.extend(quote! { #CRATE::lifetime_list::cons::Nil });
1069 return;
1070 }
1071
1072 let mut count = 1;
1073
1074 for lt in iter {
1075 count += 1;
1076 tokens.extend(
1077 quote! { , #CRATE::lifetime_list::cons::Cons<#CRATE::lifetime_list::Inv<#lt> },
1078 );
1079 }
1080
1081 if let Some(tail) = &self.tail {
1082 tokens.extend(quote! {, #tail});
1083 }
1084
1085 for _ in 0..count {
1087 tokens.extend(quote! { > });
1088 }
1089 }
1090}
1091
1092struct HoleList {
1093 count: usize,
1094 tail: Option<TokenStream>,
1095}
1096
1097impl ToTokens for HoleList {
1098 fn to_tokens(&self, tokens: &mut TokenStream) {
1099 if self.count != 0 {
1100 tokens.extend(quote! { #CRATE::lifetime_list::cons::Cons<#CRATE::lifetime_list::Hole });
1101 } else {
1102 tokens.extend(quote! { #CRATE::lifetime_list::cons::Nil });
1103 return;
1104 }
1105
1106 for _ in 0..(self.count - 1) {
1107 tokens
1108 .extend(quote! { , #CRATE::lifetime_list::cons::Cons<#CRATE::lifetime_list::Hole });
1109 }
1110
1111 if let Some(tail) = &self.tail {
1112 tokens.extend(quote! {, #tail});
1113 }
1114
1115 for _ in 0..self.count {
1117 tokens.extend(quote! { > });
1118 }
1119 }
1120}
1121
1122struct GenericTypeReplace<'a> {
1123 replacements: HashMap<&'a syn::Ident, syn::TypePath>,
1124}
1125
1126impl Fold for GenericTypeReplace<'_> {
1127 fn fold_type_path(&mut self, i: syn::TypePath) -> syn::TypePath {
1128 if i.qself.is_some() {
1129 return syn::fold::fold_type_path(self, i);
1130 }
1131
1132 let Some(ident) = i.path.get_ident() else {
1133 return syn::fold::fold_type_path(self, i);
1134 };
1135
1136 if let Some(path) = self.replacements.get(ident) {
1137 parse_quote!(#path)
1138 } else {
1139 syn::fold::fold_type_path(self, i)
1140 }
1141 }
1142}
1143
1144struct FindAndRemoveSized {
1145 sized: Option<bool>,
1146}
1147
1148impl Fold for FindAndRemoveSized {
1149 fn fold_predicate_type(&mut self, i: syn::PredicateType) -> syn::PredicateType {
1150 syn::PredicateType {
1151 lifetimes: i.lifetimes,
1152 bounded_ty: i.bounded_ty,
1153 colon_token: i.colon_token,
1154 bounds: i
1155 .bounds
1156 .into_iter()
1157 .flat_map(|bound| match &bound {
1158 syn::TypeParamBound::Trait(trait_bound) => {
1159 if trait_bound
1160 .path
1161 .get_ident()
1162 .map(|ident| ident == "Sized")
1163 .unwrap_or_default()
1164 {
1165 if matches!(self.sized, Some(false) | None) {
1166 self.sized = Some(matches!(
1167 trait_bound.modifier,
1168 syn::TraitBoundModifier::None
1169 ));
1170 }
1171
1172 None
1173 } else {
1174 Some(bound)
1175 }
1176 }
1177 _ => Some(bound),
1178 })
1179 .collect(),
1180 }
1181 }
1182}
1183
1184struct TagType<'a> {
1185 ident: &'a syn::Ident,
1186 generics: &'a Generics<'a>,
1187}
1188
1189impl<'a> TagType<'a> {
1190 fn new(ident: &'a syn::Ident, generics: &'a Generics) -> Self {
1191 Self { ident, generics }
1192 }
1193}
1194
1195impl ToTokens for TagType<'_> {
1196 fn to_tokens(&self, tokens: &mut TokenStream) {
1197 if self.generics.types_and_consts_is_empty() {
1198 self.ident.to_tokens(tokens)
1199 } else {
1200 let Self { ident, generics } = self;
1201
1202 let generics = generics.with_types_and_consts(
1203 |TypeGeneric { ident, .. }| ident,
1204 |ConstGeneric { ident, .. }| ident,
1205 );
1206
1207 tokens.extend(quote! {
1208 #ident <#(#generics),*>
1209 });
1210 }
1211 }
1212}
1213
1214struct JustTypePath;
1215
1216impl JustTypePath {
1217 fn strip_type(ty: &syn::Type) -> Option<syn::Type> {
1218 match ty {
1219 syn::Type::Path(_) => Some(JustTypePath.fold_type(ty.clone())),
1220 _ => None,
1221 }
1222 }
1223}
1224
1225impl Fold for JustTypePath {
1226 fn fold_path_segment(&mut self, mut segment: syn::PathSegment) -> syn::PathSegment {
1227 segment.arguments = syn::PathArguments::None;
1228 segment
1229 }
1230}
1231
1232struct Generics<'a> {
1233 generics: Vec<Generic<'a>>,
1234}
1235
1236enum Generic<'a> {
1237 Lifetime(LifetimeGeneric<'a>),
1238 Type(TypeGeneric<'a>),
1239 Const(ConstGeneric<'a>),
1240}
1241
1242struct LifetimeGeneric<'a> {
1243 lifetime: &'a syn::Lifetime,
1244 bounds: Vec<&'a syn::Lifetime>,
1245}
1246
1247struct TypeGeneric<'a> {
1248 ident: &'a syn::Ident,
1249 bounds: Vec<&'a syn::TypeParamBound>,
1250 default: Option<&'a syn::Type>,
1251 is_itself: bool,
1252}
1253
1254struct ConstGeneric<'a> {
1255 ident: &'a syn::Ident,
1256 ty: &'a syn::Type,
1257 default: Option<&'a syn::Expr>,
1258}
1259
1260impl<'a> Generics<'a> {
1261 fn new<T: IntoIterator<Item = &'a syn::GenericParam>>(generics: T) -> syn::Result<Self> {
1262 Ok(Self {
1263 generics: generics
1264 .into_iter()
1265 .map(|generic| {
1266 Ok(match generic {
1267 syn::GenericParam::Lifetime(lifetime_param) => {
1268 if let Some(attr) = lifetime_param.attrs.first() {
1269 return Err(syn::Error::new_spanned(attr, "unknown attribute"));
1270 }
1271
1272 Generic::Lifetime(LifetimeGeneric {
1273 lifetime: &lifetime_param.lifetime,
1274 bounds: lifetime_param.bounds.iter().collect(),
1275 })
1276 }
1277 syn::GenericParam::Type(type_param) => {
1278 let mut is_itself = false;
1279
1280 for attr in &type_param.attrs {
1281 if matches!(attr.style, syn::AttrStyle::Inner(_)) {
1282 return Err(syn::Error::new_spanned(
1283 attr,
1284 "inner attribute not allowed",
1285 ));
1286 }
1287
1288 match &attr.meta {
1289 syn::Meta::Path(path)
1290 if path
1291 .get_ident()
1292 .map(|ident| ident == "itself")
1293 .unwrap_or_default() =>
1294 {
1295 if is_itself {
1296 return Err(syn::Error::new_spanned(
1297 attr,
1298 "cannot set `itself` more than once",
1299 ));
1300 }
1301
1302 is_itself = true;
1303 }
1304 _ => {
1305 return Err(syn::Error::new_spanned(
1306 attr,
1307 "unknown attribute",
1308 ));
1309 }
1310 }
1311 }
1312
1313 Generic::Type(TypeGeneric {
1314 ident: &type_param.ident,
1315 bounds: type_param.bounds.iter().collect(),
1316 default: type_param.default.as_ref(),
1317 is_itself,
1318 })
1319 }
1320 syn::GenericParam::Const(const_param) => {
1321 if let Some(attr) = const_param.attrs.first() {
1322 return Err(syn::Error::new_spanned(attr, "unknown attribute"));
1323 }
1324
1325 Generic::Const(ConstGeneric {
1326 ident: &const_param.ident,
1327 ty: &const_param.ty,
1328 default: const_param.default.as_ref(),
1329 })
1330 }
1331 })
1332 })
1333 .collect::<syn::Result<_>>()?,
1334 })
1335 }
1336
1337 fn is_empty(&self) -> bool {
1338 self.generics.is_empty()
1339 }
1340
1341 fn types_is_empty(&self) -> bool {
1342 !self
1343 .generics
1344 .iter()
1345 .any(|generic| matches!(generic, Generic::Type(_)))
1346 }
1347
1348 fn lifetimes_is_empty(&self) -> bool {
1349 !self
1350 .generics
1351 .iter()
1352 .any(|generic| matches!(generic, Generic::Lifetime(_)))
1353 }
1354
1355 fn types_and_consts_is_empty(&self) -> bool {
1356 !self
1357 .generics
1358 .iter()
1359 .any(|generic| matches!(generic, Generic::Type(_) | Generic::Const(_)))
1360 }
1361
1362 fn with_types<'b, T, R>(&'b self, mut t: T) -> impl Iterator<Item = R> + use<'b, T, R>
1363 where
1364 T: FnMut(&'b TypeGeneric) -> R,
1365 {
1366 self.generics.iter().flat_map(move |generic| match generic {
1367 Generic::Type(ty) => Some(t(ty)),
1368 _ => None,
1369 })
1370 }
1371
1372 fn with_types_and_consts<'b, T, C, R>(
1373 &'b self,
1374 mut t: T,
1375 mut c: C,
1376 ) -> impl Iterator<Item = R> + use<'b, T, C, R>
1377 where
1378 T: FnMut(&'b TypeGeneric) -> R,
1379 C: FnMut(&'b ConstGeneric) -> R,
1380 {
1381 self.generics.iter().flat_map(move |generic| match generic {
1382 Generic::Type(ty) => Some(t(ty)),
1383 Generic::Const(cons) => Some(c(cons)),
1384 _ => None,
1385 })
1386 }
1387
1388 fn with_lifetimes<'b, L, R>(&'b self, mut l: L) -> impl Iterator<Item = R> + use<'b, L, R>
1389 where
1390 L: FnMut(&'b LifetimeGeneric) -> R,
1391 {
1392 self.generics.iter().flat_map(move |generic| match generic {
1393 Generic::Lifetime(lifetime) => Some(l(lifetime)),
1394 _ => None,
1395 })
1396 }
1397
1398 fn with<'b, L, T, C, R>(
1399 &'b self,
1400 mut l: L,
1401 mut t: T,
1402 mut c: C,
1403 ) -> impl Iterator<Item = R> + use<'b, L, T, C, R>
1404 where
1405 L: FnMut(&'b LifetimeGeneric) -> R,
1406 T: FnMut(&'b TypeGeneric) -> R,
1407 C: FnMut(&'b ConstGeneric) -> R,
1408 {
1409 self.generics.iter().map(move |generic| match generic {
1410 Generic::Lifetime(lifetime) => l(lifetime),
1411 Generic::Type(ty) => t(ty),
1412 Generic::Const(cons) => c(cons),
1413 })
1414 }
1415}
1416
1417struct Attributes<'a> {
1418 docs: Vec<&'a syn::Attribute>,
1419 struct_attrs: Vec<&'a syn::Attribute>,
1420 impl_attrs: Vec<&'a syn::Attribute>,
1421}
1422
1423impl<'a> Attributes<'a> {
1424 fn new<I: IntoIterator<Item = &'a syn::Attribute>>(attrs: I) -> syn::Result<Self> {
1425 let mut docs = Vec::new();
1426 let mut struct_attrs = Vec::new();
1427 let mut impl_attrs = Vec::new();
1428
1429 for attr in attrs {
1430 if let Some(ident) = attr.path().get_ident() {
1431 match &*ident.to_string() {
1432 "expect" => {
1435 struct_attrs.push(attr);
1436 }
1437 "allow" | "warn" | "deny" | "forbid" => {
1439 struct_attrs.push(attr);
1440 impl_attrs.push(attr);
1441 }
1442 "cfg" => {}
1445 "deprecated" => {
1447 struct_attrs.push(attr);
1448 }
1449 "doc" | "doc_cfg" => {
1452 docs.push(attr);
1453 }
1454 _ => {
1457 return Err(syn::Error::new_spanned(attr, "unknown attribute"));
1458 }
1459 }
1460 } else {
1461 return Err(syn::Error::new_spanned(attr, "unknown attribute"));
1464 }
1465 }
1466
1467 Ok(Self {
1468 docs,
1469 struct_attrs,
1470 impl_attrs,
1471 })
1472 }
1473}