11use proc_macro2:: TokenStream ;
2- use quote:: quote;
2+ use quote:: { ToTokens , TokenStreamExt , quote} ;
33use syn:: {
4- Attribute , Expr , Lit , Meta , Signature , Visibility , parse:: Parse , punctuated:: Punctuated ,
4+ Attribute , Expr , ExprLit , Ident , Lit , Meta , Path , Signature , Token , Visibility , parse:: Parse ,
5+ punctuated:: Punctuated ,
56} ;
67
7- type AttributeArgs = Punctuated < syn :: Meta , syn :: Token ! [ , ] > ;
8+ use crate :: { retrieve_driver_mod , retrieve_runtime_mod } ;
89
10+ struct MetaPunctuated ( Punctuated < Meta , Token ! [ , ] > ) ;
11+
12+ impl Parse for MetaPunctuated {
13+ fn parse ( input : syn:: parse:: ParseStream ) -> syn:: Result < Self > {
14+ Ok ( Self ( Punctuated :: parse_terminated ( input) ?) )
15+ }
16+ }
17+
18+ pub ( crate ) struct BuilderMethod {
19+ pub name : Ident ,
20+ pub value : Expr ,
21+ }
22+
23+ #[ derive( Default ) ]
924pub ( crate ) struct RawAttr {
10- pub inner_attrs : AttributeArgs ,
25+ pub runtime_methods : Vec < BuilderMethod > ,
26+ pub proactor_methods : Vec < BuilderMethod > ,
27+ pub crate_name : Option < TokenStream > ,
28+ pub with_proactor_call : Option < Path > ,
1129}
1230
1331impl Parse for RawAttr {
1432 fn parse ( input : syn:: parse:: ParseStream ) -> syn:: Result < Self > {
15- let inner_attrs = AttributeArgs :: parse_terminated ( input) ?;
16- Ok ( Self { inner_attrs } )
33+ let items = Punctuated :: < Meta , Token ! [ , ] > :: parse_terminated ( input) ?;
34+
35+ let mut runtime_methods = Vec :: new ( ) ;
36+ let mut proactor_methods = Vec :: new ( ) ;
37+ let mut crate_name = None ;
38+ let mut with_proactor_call = None ;
39+
40+ for meta in items {
41+ match meta {
42+ Meta :: List ( list) => {
43+ if list. path . is_ident ( "with_proactor" ) {
44+ if !list. tokens . is_empty ( ) {
45+ let inner_items = syn:: parse2 :: < MetaPunctuated > ( list. tokens ) ?. 0 ;
46+ for inner_meta in inner_items {
47+ if let Meta :: NameValue ( nv) = inner_meta {
48+ let name = nv. path . require_ident ( ) ?. clone ( ) ;
49+ proactor_methods. push ( BuilderMethod {
50+ name,
51+ value : nv. value ,
52+ } ) ;
53+ } else {
54+ return Err ( syn:: Error :: new_spanned (
55+ inner_meta,
56+ "expected `name = value` inside `with_proactor`" ,
57+ ) ) ;
58+ }
59+ }
60+ with_proactor_call = Some ( list. path . clone ( ) ) ;
61+ }
62+ } else {
63+ return Err ( syn:: Error :: new_spanned (
64+ list. path ,
65+ "unknown key; use `name = value` for parameters or \
66+ `with_proactor(...)` for proactor config",
67+ ) ) ;
68+ }
69+ }
70+ Meta :: NameValue ( nv) => {
71+ if nv. path . is_ident ( "crate" ) {
72+ if let Expr :: Lit ( ExprLit {
73+ lit : Lit :: Str ( s) , ..
74+ } ) = & nv. value
75+ {
76+ crate_name = Some ( s. parse :: < TokenStream > ( ) . unwrap ( ) ) ;
77+ } else {
78+ return Err ( syn:: Error :: new_spanned (
79+ & nv. value ,
80+ "expected a string literal for `crate`" ,
81+ ) ) ;
82+ }
83+ } else {
84+ let name = nv. path . require_ident ( ) ?. clone ( ) ;
85+ runtime_methods. push ( BuilderMethod {
86+ name,
87+ value : nv. value ,
88+ } ) ;
89+ }
90+ }
91+ Meta :: Path ( path) => {
92+ return Err ( syn:: Error :: new_spanned (
93+ path,
94+ "expected `name = value` or `with_proactor(...)`" ,
95+ ) ) ;
96+ }
97+ }
98+ }
99+
100+ Ok ( Self {
101+ runtime_methods,
102+ proactor_methods,
103+ crate_name,
104+ with_proactor_call,
105+ } )
17106 }
18107}
19108
20109pub ( crate ) struct RawBodyItemFn {
21110 pub attrs : Vec < Attribute > ,
22- pub args : AttributeArgs ,
111+ pub args : RawAttr ,
23112 pub vis : Visibility ,
24113 pub sig : Signature ,
25114 pub body : TokenStream ,
@@ -29,37 +118,88 @@ impl RawBodyItemFn {
29118 pub fn new ( attrs : Vec < Attribute > , vis : Visibility , sig : Signature , body : TokenStream ) -> Self {
30119 Self {
31120 attrs,
32- args : AttributeArgs :: new ( ) ,
121+ args : RawAttr :: default ( ) ,
33122 vis,
34123 sig,
35124 body,
36125 }
37126 }
38127
39- pub fn set_args ( & mut self , args : AttributeArgs ) {
128+ pub fn set_args ( & mut self , args : RawAttr ) {
40129 self . args = args;
41130 }
42131
43- pub fn crate_name ( & self ) -> Option < TokenStream > {
44- for attr in & self . args {
45- if let Meta :: NameValue ( name) = & attr {
46- let ident = name
47- . path
48- . get_ident ( )
49- . map ( |ident| ident. to_string ( ) . to_lowercase ( ) )
50- . unwrap_or_default ( ) ;
51- if ident == "crate" {
52- if let Expr :: Lit ( lit) = & name. value
53- && let Lit :: Str ( s) = & lit. lit
54- {
55- let crate_name = s. parse :: < TokenStream > ( ) . unwrap ( ) ;
56- return Some ( quote ! ( #crate_name:: runtime) ) ;
57- }
58- } else {
59- panic ! ( "Unsupported property {ident}" ) ;
60- }
132+ pub fn emit_fn_to_tokens ( & self , tokens : & mut TokenStream ) {
133+ tokens. append_all (
134+ self . attrs
135+ . iter ( )
136+ . filter ( |a| matches ! ( a. style, syn:: AttrStyle :: Outer ) ) ,
137+ ) ;
138+ self . vis . to_tokens ( tokens) ;
139+ self . sig . to_tokens ( tokens) ;
140+ tokens. append_all ( self . gen_runtime_block ( ) ) ;
141+ }
142+
143+ fn gen_runtime_block ( & self ) -> TokenStream {
144+ let runtime_mod = match & self . args . crate_name {
145+ Some ( c) => {
146+ let c = c. clone ( ) ;
147+ quote ! ( #c:: runtime)
148+ }
149+ None => retrieve_runtime_mod ( ) ,
150+ } ;
151+
152+ let driver_mod = match & self . args . crate_name {
153+ Some ( c) => {
154+ let c = c. clone ( ) ;
155+ quote ! ( #c:: driver)
61156 }
157+ None => retrieve_driver_mod ( ) ,
158+ } ;
159+
160+ let block = & self . body ;
161+
162+ let mut builder = quote ! {
163+ #runtime_mod:: Runtime :: builder( )
164+ } ;
165+
166+ for method in & self . args . runtime_methods {
167+ let name = & method. name ;
168+ let value = & method. value ;
169+ builder = quote ! {
170+ #builder. #name( #value)
171+ } ;
62172 }
63- None
173+
174+ if !self . args . proactor_methods . is_empty ( ) {
175+ let mut proactor_stmts: Vec < TokenStream > = Vec :: new ( ) ;
176+ proactor_stmts. push ( quote ! {
177+ let mut __compio_proactor_builder = #driver_mod:: Proactor :: builder( ) ;
178+ } ) ;
179+ for method in & self . args . proactor_methods {
180+ let name = & method. name ;
181+ let value = & method. value ;
182+ proactor_stmts. push ( quote ! {
183+ __compio_proactor_builder. #name( #value) ;
184+ } ) ;
185+ }
186+ // Preserve the original token for the `with_proactor` call to make the language
187+ // server work better.
188+ let with_proactor_call = if let Some ( path) = & self . args . with_proactor_call {
189+ quote ! ( #path)
190+ } else {
191+ quote ! ( with_proactor)
192+ } ;
193+ builder = quote ! {
194+ #builder. #with_proactor_call( {
195+ #( #proactor_stmts) *
196+ __compio_proactor_builder
197+ } )
198+ } ;
199+ }
200+
201+ quote ! ( {
202+ #builder. build( ) . expect( "cannot create runtime" ) . block_on( async move #block)
203+ } )
64204 }
65205}
0 commit comments