|
6 | 6 | // option. This file may not be copied, modified, or distributed
|
7 | 7 | // except according to those terms.
|
8 | 8 |
|
9 |
| -use proc_macro2::{Span, TokenStream}; |
10 |
| -use quote::quote; |
11 |
| -use syn::{ |
12 |
| - parse::{Parse, ParseStream}, |
13 |
| - parse_macro_input, parse_quote, |
14 |
| - punctuated::Punctuated, |
15 |
| - token::Comma, |
16 |
| - Ident, ItemTrait, Path, PredicateType, Result, ReturnType, Token, TraitBound, |
17 |
| - TraitBoundModifier, TraitItem, Type, WherePredicate, |
18 |
| -}; |
19 |
| - |
20 |
| -struct Attrs { |
21 |
| - traits: Punctuated<Transform, Comma>, |
22 |
| -} |
23 |
| - |
24 |
| -impl Parse for Attrs { |
25 |
| - fn parse(input: ParseStream) -> Result<Self> { |
26 |
| - Ok(Self { |
27 |
| - traits: input.parse_terminated(Transform::parse, Token![,])?, |
28 |
| - }) |
29 |
| - } |
30 |
| -} |
31 |
| - |
32 |
| -struct Transform { |
33 |
| - subtrait_name: Ident, |
34 |
| - #[allow(dead_code)] |
35 |
| - colon: Token![:], |
36 |
| - subtrait: Path, |
37 |
| -} |
38 |
| - |
39 |
| -impl Parse for Transform { |
40 |
| - fn parse(input: ParseStream) -> Result<Self> { |
41 |
| - Ok(Self { |
42 |
| - subtrait_name: input.parse()?, |
43 |
| - colon: input.parse()?, |
44 |
| - subtrait: input.parse()?, |
45 |
| - }) |
46 |
| - } |
47 |
| -} |
| 9 | +mod transformer; |
48 | 10 |
|
49 | 11 | #[proc_macro_attribute]
|
50 | 12 | pub fn trait_transformer(
|
51 | 13 | attr: proc_macro::TokenStream,
|
52 | 14 | item: proc_macro::TokenStream,
|
53 | 15 | ) -> proc_macro::TokenStream {
|
54 |
| - let attrs = parse_macro_input!(attr as Attrs); |
55 |
| - let item = parse_macro_input!(item as ItemTrait); |
56 |
| - |
57 |
| - let transformed_trait = transform_trait(&attrs, &item); |
58 |
| - let output = quote! { |
59 |
| - #item |
60 |
| - #transformed_trait |
61 |
| - }; |
62 |
| - |
63 |
| - output.into() |
64 |
| -} |
65 |
| - |
66 |
| -fn transform_trait(attrs: &Attrs, tr: &ItemTrait) -> TokenStream { |
67 |
| - let traits = attrs |
68 |
| - .traits |
69 |
| - .iter() |
70 |
| - .map(|attr| { |
71 |
| - let subtrait = &attr.subtrait; |
72 |
| - let fn_bounds = tr.items.iter().filter_map(|item| { |
73 |
| - match item { |
74 |
| - TraitItem::Fn(item_fn) => { |
75 |
| - let is_async = item_fn.sig.asyncness.is_some(); |
76 |
| - let returns_impl_trait = |
77 |
| - if let ReturnType::Type(_, ty) = &item_fn.sig.output { |
78 |
| - matches!(**ty, Type::ImplTrait(_)) |
79 |
| - } else { |
80 |
| - false |
81 |
| - }; |
82 |
| - |
83 |
| - if is_async || returns_impl_trait { |
84 |
| - let name = &item_fn.sig.ident; |
85 |
| - return Some(quote! { #name(): #subtrait }); |
86 |
| - } |
87 |
| - } |
88 |
| - _ => (), |
89 |
| - } |
90 |
| - None |
91 |
| - }); |
92 |
| - |
93 |
| - let tr_ident = &tr.ident; |
94 |
| - let supertrait = syn::TypeParamBound::Verbatim(quote! { |
95 |
| - #tr_ident<#(#fn_bounds),*> |
96 |
| - }); |
97 |
| - |
98 |
| - ItemTrait { |
99 |
| - attrs: Vec::new(), |
100 |
| - ident: attr.subtrait_name.clone(), |
101 |
| - items: Vec::new(), |
102 |
| - supertraits: Punctuated::from_iter(vec![ |
103 |
| - supertrait, |
104 |
| - syn::TypeParamBound::Trait(TraitBound { |
105 |
| - paren_token: None, |
106 |
| - modifier: TraitBoundModifier::None, |
107 |
| - lifetimes: None, |
108 |
| - path: attr.subtrait.clone(), |
109 |
| - }), |
110 |
| - ].into_iter()), |
111 |
| - ..tr.clone() |
112 |
| - } |
113 |
| - }) |
114 |
| - .collect::<Vec<_>>(); |
115 |
| - |
116 |
| - quote! { #(#traits)* } |
| 16 | + transformer::trait_transformer(attr, item) |
117 | 17 | }
|
0 commit comments