@@ -6,17 +6,32 @@ use crate::lifetime::TraitContext;
66use crate :: utils:: * ;
77
88pub fn expand ( attr : TokenStream , input : TokenStream ) -> Result < TokenStream > {
9+ let rename = syn:: parse2 :: < Option < Ident > > ( attr) ?;
910 let input_item = syn:: parse2 :: < syn:: Item > ( input. clone ( ) ) ?;
10- // TODO: support non-trait items
11- let mut dyn_trait = as_variant ! ( input_item, syn:: Item :: Trait )
12- . ok_or_else ( || syn:: Error :: new_spanned ( & input, "non-trait item is not supported yet" ) ) ?;
13- let mut trait_impl_items = TokenStream :: new ( ) ;
11+ let output = match input_item {
12+ syn:: Item :: Trait ( t) => expand_trait ( rename, t) ?,
13+ syn:: Item :: Fn ( f) => expand_fn ( rename, f) ?,
14+ item => {
15+ return Err ( syn:: Error :: new_spanned (
16+ & item,
17+ "expected a `fn` or `trait` item" ,
18+ ) )
19+ } ,
20+ } ;
21+ Ok ( quote ! (
22+ #[ allow( async_fn_in_trait) ]
23+ #input
24+ #output
25+ ) )
26+ }
1427
15- let dyn_trait_name = syn:: parse2 :: < Option < Ident > > ( attr ) ?
16- . unwrap_or_else ( || format_ident ! ( "Dyn{}" , dyn_trait. ident) ) ;
17- let trait_name = std:: mem:: replace ( & mut dyn_trait. ident , dyn_trait_name) ;
28+ fn expand_trait ( rename : Option < Ident > , mut dyn_trait : syn:: ItemTrait ) -> Result < TokenStream > {
29+ let dyn_trait_name = rename . unwrap_or_else ( || format_ident ! ( "Dyn{}" , dyn_trait. ident) ) ;
30+ let input_trait_name = std:: mem:: replace ( & mut dyn_trait. ident , dyn_trait_name) ;
1831 let dyn_trait_name = & dyn_trait. ident ;
19- let impl_target = format_ident ! ( "{}Implementor" , trait_name) ;
32+
33+ let impl_target = format_ident ! ( "{}Implementor" , input_trait_name) ;
34+ let mut trait_impl_items = TokenStream :: new ( ) ;
2035
2136 let ( _, ty_generics, where_clause) = dyn_trait. generics . split_for_impl ( ) ;
2237 for item in dyn_trait. items . iter_mut ( ) {
@@ -51,11 +66,17 @@ pub fn expand(attr: TokenStream, input: TokenStream) -> Result<TokenStream> {
5166 let context = TraitContext {
5267 generics : & dyn_trait. generics ,
5368 } ;
54- let transformed = transform_fn ( & context, sig, false ) ?;
69+ let transformed = transform_fn ( Some ( & context) , sig, false ) ?;
5570 // TODO: support `#[dynify(skip)]`
71+ // TODO: support nested `#[dynify]`
5672 let attrs_outer = attrs. outer ( ) ;
5773 let attrs_inner = attrs. inner ( ) ;
58- let impl_body = quote_transformed_body ( transformed, & impl_target, sig) ;
74+ let target = quote_with ( |tokens| {
75+ impl_target. to_tokens ( tokens) ;
76+ NewToken ! [ :: ] . to_tokens ( tokens) ;
77+ sig. ident . to_tokens ( tokens) ;
78+ } ) ;
79+ let impl_body = quote_transformed_body ( transformed, & target, sig) ;
5980 quote ! ( #( #attrs_outer) * #sig { #( #attrs_inner) * #impl_body } )
6081 } ,
6182 _ => continue ,
@@ -65,27 +86,36 @@ pub fn expand(attr: TokenStream, input: TokenStream) -> Result<TokenStream> {
6586
6687 let impl_generics = quote_impl_generics ( & dyn_trait. generics ) ;
6788 Ok ( quote ! (
68- #[ allow( async_fn_in_trait) ]
69- #input
70-
7189 #[ allow( async_fn_in_trait) ]
7290 #[ allow( clippy:: type_complexity) ]
7391 #dyn_trait
7492
7593 #[ allow( clippy:: type_complexity) ]
76- impl <#impl_generics #impl_target: #trait_name #ty_generics>
94+ impl <#impl_generics #impl_target: #input_trait_name #ty_generics>
7795 #dyn_trait_name #ty_generics for #impl_target
7896 #where_clause { #trait_impl_items }
7997 ) )
8098}
8199
100+ fn expand_fn ( rename : Option < Ident > , mut dyn_fn : syn:: ItemFn ) -> Result < TokenStream > {
101+ let syn:: ItemFn { sig, attrs, .. } = & mut dyn_fn;
102+
103+ let dyn_fn_name = rename. unwrap_or_else ( || format_ident ! ( "dyn_{}" , sig. ident) ) ;
104+ let input_fn_name = std:: mem:: replace ( & mut sig. ident , dyn_fn_name) ;
105+
106+ let transformed = transform_fn ( None , sig, true ) ?;
107+ let attrs_outer = attrs. outer ( ) ;
108+ let attrs_inner = attrs. inner ( ) ;
109+ let impl_body = quote_transformed_body ( transformed, & input_fn_name, sig) ;
110+ Ok ( quote ! ( #( #attrs_outer) * #sig { #( #attrs_inner) * #impl_body } ) )
111+ }
112+
82113/// Generates implementation body for a transformed function.
83114fn quote_transformed_body (
84115 transformed : TransformResult ,
85- target : & Ident ,
116+ target : & dyn ToTokens ,
86117 sig : & syn:: Signature ,
87118) -> impl ToTokens {
88- let ident = & sig. ident ;
89119 let arg_idents = sig. inputs . pairs ( ) . map ( |p| {
90120 quote_with ( move |tokens| {
91121 match p. value ( ) {
@@ -95,16 +125,17 @@ fn quote_transformed_body(
95125 p. punct_or_default ( ) . to_tokens ( tokens) ;
96126 } )
97127 } ) ;
128+
98129 match transformed {
99130 TransformResult :: Noop if sig. asyncness . is_some ( ) => {
100- quote ! ( #target:: #ident ( #( #arg_idents) * ) . await )
131+ quote ! ( #target ( #( #arg_idents) * ) . await )
101132 } ,
102133 TransformResult :: Noop => {
103- quote ! ( #target:: #ident ( #( #arg_idents) * ) )
134+ quote ! ( #target ( #( #arg_idents) * ) )
104135 } ,
105136 TransformResult :: Function | TransformResult :: Method => {
106137 let recv = sig. receiver ( ) . map ( |r| & r. self_token ) ;
107- quote ! ( :: dynify:: __from_fn!( [ #recv] #target:: #ident , #( #arg_idents) * ) )
138+ quote ! ( :: dynify:: __from_fn!( [ #recv] #target, #( #arg_idents) * ) )
108139 } ,
109140 }
110141}
@@ -135,25 +166,32 @@ enum TransformResult {
135166/// Transforms the supplied function into a dynified one, returning `true` only
136167/// if the transformation is successful.
137168fn transform_fn (
138- context : & TraitContext ,
169+ context : Option < & TraitContext > ,
139170 sig : & mut syn:: Signature ,
140171 force : bool ,
141172) -> Result < TransformResult > {
142173 let fn_span = sig. ident . span ( ) ;
143174 if sig. asyncness . is_none ( ) && get_impl_type ( & sig. output ) . is_none ( ) {
144- return Ok ( TransformResult :: Noop ) ;
175+ if force {
176+ return Err ( syn:: Error :: new (
177+ fn_span,
178+ "input function must return an `impl` type" ,
179+ ) ) ;
180+ } else {
181+ return Ok ( TransformResult :: Noop ) ;
182+ }
145183 }
146184
147185 let sealed_recv = match sig. receiver ( ) {
148186 Some ( r) => crate :: receiver:: infer_receiver ( r)
149- . ok_or_else ( || syn:: Error :: new ( r. self_token . span , "cannot determine receiver type" ) )
187+ . ok_or_else ( || syn:: Error :: new ( r. self_token . span , "unsupported receiver type" ) )
150188 . map ( Some ) ?,
151189 None if force => None ,
152190 None => return Ok ( TransformResult :: Noop ) ,
153191 } ;
154192
155193 let output_lifetime = Lifetime :: new ( "'dynify" , fn_span) ;
156- crate :: lifetime:: inject_output_lifetime ( Some ( context) , sig, & output_lifetime) ?;
194+ crate :: lifetime:: inject_output_lifetime ( context, sig, & output_lifetime) ?;
157195
158196 // Infer the appropriate output type
159197 let input_types = quote_with ( |tokens| {
@@ -174,7 +212,7 @@ fn transform_fn(
174212 } ) ;
175213 let output_type = match & sig. output {
176214 ReturnType :: Default => ReturnType :: Type (
177- < Token ! [ ->] > :: default ( ) ,
215+ NewToken ! [ ->] ,
178216 parse_quote_spanned ! ( fn_span => :: dynify:: r#priv:: Fn <
179217 ( #input_types) ,
180218 dyn #output_lifetime + :: core:: future:: Future <Output = ( ) >
0 commit comments