11use proc_macro2:: TokenStream ;
22use quote:: { format_ident, quote, ToTokens } ;
3- use syn:: { parse_quote_spanned, FnArg , Ident , Lifetime , Result , ReturnType , Token , Type } ;
3+ use syn:: parse:: ParseStream ;
4+ use syn:: {
5+ parse_quote, parse_quote_spanned, FnArg , Ident , Lifetime , LitStr , Result , ReturnType , Token ,
6+ Type ,
7+ } ;
48
59use crate :: lifetime:: TraitContext ;
610use crate :: utils:: * ;
711
812pub fn expand ( attr : TokenStream , input : TokenStream ) -> Result < TokenStream > {
9- let rename = syn:: parse2 :: < Option < Ident > > ( attr) ?;
13+ let opts = syn:: parse2 :: < Options > ( attr) ?;
1014 let input_item = syn:: parse2 :: < syn:: Item > ( input. clone ( ) ) ?;
15+
16+ let is_remote = opts. remote . is_some ( ) ;
1117 let output = match input_item {
12- syn:: Item :: Trait ( t) => expand_trait ( rename , t) ?,
13- syn:: Item :: Fn ( f) => expand_fn ( rename , f) ?,
18+ syn:: Item :: Trait ( t) => expand_trait ( opts , t) ?,
19+ syn:: Item :: Fn ( f) => expand_fn ( opts , f) ?,
1420 item => {
1521 return Err ( syn:: Error :: new_spanned (
1622 & item,
1723 "expected a `fn` or `trait` item" ,
1824 ) )
1925 } ,
2026 } ;
21- Ok ( quote ! (
22- #[ allow( async_fn_in_trait) ]
23- #input
24- #output
25- ) )
26- }
2727
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) ;
31- let dyn_trait_name = & dyn_trait. ident ;
28+ let input = ( !is_remote) . then_some ( input) ;
29+ Ok ( quote ! ( #input #output) )
30+ }
3231
33- let impl_target = format_ident ! ( "{}Implementor" , input_trait_name) ;
34- let mut trait_impl_items = TokenStream :: new ( ) ;
32+ fn expand_trait ( opts : Options , mut dyn_trait : syn:: ItemTrait ) -> Result < TokenStream > {
33+ let target_trait = if let Some ( remote) = opts. remote {
34+ remote
35+ } else {
36+ let dyn_trait_name = opts
37+ . rename
38+ . unwrap_or_else ( || format_ident ! ( "Dyn{}" , dyn_trait. ident) ) ;
39+ let target_trait_name = std:: mem:: replace ( & mut dyn_trait. ident , dyn_trait_name) ;
40+ parse_quote ! ( #target_trait_name)
41+ } ;
3542
43+ let impl_target = {
44+ let target_trait_name = & target_trait. segments . last ( ) . unwrap ( ) . ident ;
45+ format_ident ! ( "{}Implementor" , target_trait_name)
46+ } ;
3647 let ( _, ty_generics, where_clause) = dyn_trait. generics . split_for_impl ( ) ;
48+
49+ let mut trait_impl_items = TokenStream :: new ( ) ;
3750 for item in dyn_trait. items . iter_mut ( ) {
3851 let impl_item = match item {
3952 syn:: TraitItem :: Const ( syn:: TraitItemConst {
@@ -71,12 +84,12 @@ fn expand_trait(rename: Option<Ident>, mut dyn_trait: syn::ItemTrait) -> Result<
7184 // TODO: support nested `#[dynify]`
7285 let attrs_outer = attrs. outer ( ) ;
7386 let attrs_inner = attrs. inner ( ) ;
74- let target = quote_with ( |tokens| {
87+ let target_fn = quote_with ( |tokens| {
7588 impl_target. to_tokens ( tokens) ;
7689 NewToken ! [ :: ] . to_tokens ( tokens) ;
7790 sig. ident . to_tokens ( tokens) ;
7891 } ) ;
79- let impl_body = quote_transformed_body ( transformed, & target , sig) ;
92+ let impl_body = quote_transformed_body ( transformed, & target_fn , sig) ;
8093 quote ! ( #( #attrs_outer) * #sig { #( #attrs_inner) * #impl_body } )
8194 } ,
8295 _ => continue ,
@@ -85,33 +98,42 @@ fn expand_trait(rename: Option<Ident>, mut dyn_trait: syn::ItemTrait) -> Result<
8598 }
8699
87100 let impl_generics = quote_impl_generics ( & dyn_trait. generics ) ;
101+ let dyn_trait_name = & dyn_trait. ident ;
102+
88103 Ok ( quote ! (
89104 #[ allow( async_fn_in_trait) ]
90105 #[ allow( clippy:: type_complexity) ]
91106 #dyn_trait
92107
93108 #[ allow( clippy:: type_complexity) ]
94- impl <#impl_generics #impl_target: #input_trait_name #ty_generics>
109+ impl <#impl_generics #impl_target: #target_trait #ty_generics>
95110 #dyn_trait_name #ty_generics for #impl_target
96111 #where_clause { #trait_impl_items }
97112 ) )
98113}
99114
100- fn expand_fn ( rename : Option < Ident > , mut dyn_fn : syn:: ItemFn ) -> Result < TokenStream > {
115+ fn expand_fn ( opts : Options , mut dyn_fn : syn:: ItemFn ) -> Result < TokenStream > {
101116 let syn:: ItemFn {
102117 vis,
103118 sig,
104119 attrs,
105120 block : _,
106121 } = & mut dyn_fn;
107122
108- let dyn_fn_name = rename. unwrap_or_else ( || format_ident ! ( "dyn_{}" , sig. ident) ) ;
109- let input_fn_name = std:: mem:: replace ( & mut sig. ident , dyn_fn_name) ;
123+ let target_fn = if let Some ( remote) = opts. remote {
124+ remote
125+ } else {
126+ let dyn_fn_name = opts
127+ . rename
128+ . unwrap_or_else ( || format_ident ! ( "dyn_{}" , sig. ident) ) ;
129+ let target_fn_name = std:: mem:: replace ( & mut sig. ident , dyn_fn_name) ;
130+ parse_quote ! ( #target_fn_name)
131+ } ;
110132
111133 let transformed = transform_fn ( None , sig, true ) ?;
112134 let attrs_outer = attrs. outer ( ) ;
113135 let attrs_inner = attrs. inner ( ) ;
114- let impl_body = quote_transformed_body ( transformed, & input_fn_name , sig) ;
136+ let impl_body = quote_transformed_body ( transformed, & target_fn , sig) ;
115137 Ok ( quote ! ( #( #attrs_outer) * #vis #sig { #( #attrs_inner) * #impl_body } ) )
116138}
117139
@@ -259,6 +281,39 @@ fn get_impl_type(ty: &ReturnType) -> Option<(Token![->], &syn::TypeImplTrait)> {
259281 . and_then ( |( r, ty) | as_variant ! ( & * * ty, Type :: ImplTrait ) . map ( |ty| ( * r, ty) ) )
260282}
261283
284+ struct Options {
285+ rename : Option < Ident > ,
286+ remote : Option < syn:: Path > ,
287+ }
288+
289+ impl syn:: parse:: Parse for Options {
290+ fn parse ( input : ParseStream ) -> Result < Options > {
291+ syn:: custom_keyword!( remote) ;
292+
293+ let mut attrs = Options {
294+ rename : None ,
295+ remote : None ,
296+ } ;
297+
298+ // The syntax for specifying arbitrary tokens as the value of an option
299+ // follows those used in [serde](https://github.com/serde-rs/serde).
300+ if input. peek2 ( Token ! [ =] ) {
301+ let remote_token = input. parse :: < remote > ( ) ?;
302+ let _eq_token = input. parse :: < Token ! [ =] > ( ) ?;
303+ let remote = input. parse :: < LitStr > ( ) ?. parse :: < syn:: Path > ( ) ?;
304+ if remote. segments . is_empty ( ) {
305+ return Err ( syn:: Error :: new ( remote_token. span , "invalid remote type" ) ) ;
306+ }
307+ attrs. remote = Some ( remote) ;
308+ } else if !input. is_empty ( ) {
309+ attrs. rename = Some ( input. parse ( ) ?) ;
310+ }
311+ input. parse :: < syn:: parse:: Nothing > ( ) ?;
312+
313+ Ok ( attrs)
314+ }
315+ }
316+
262317#[ cfg( test) ]
263318#[ path = "dynify_tests.rs" ]
264319mod tests;
0 commit comments