@@ -2,6 +2,15 @@ use proc_macro::TokenStream;
22use quote:: { quote, quote_spanned} ;
33use syn:: { ItemFn , parse_macro_input, spanned:: Spanned } ;
44
5+ fn returns_unit ( output : & syn:: ReturnType ) -> bool {
6+ match output {
7+ syn:: ReturnType :: Default => true ,
8+ syn:: ReturnType :: Type ( _, ty) => {
9+ matches ! ( & * * ty, syn:: Type :: Tuple ( tuple) if tuple. elems. is_empty( ) )
10+ }
11+ }
12+ }
13+
514#[ proc_macro_attribute]
615pub fn attr_macro_main ( _attr : TokenStream , item : TokenStream ) -> TokenStream {
716 let input = parse_macro_input ! ( item as ItemFn ) ;
@@ -84,6 +93,149 @@ pub fn attr_macro_test(_attr: TokenStream, item: TokenStream) -> TokenStream {
8493 . into ( )
8594}
8695
96+ #[ proc_macro_attribute]
97+ pub fn attr_macro_main_p3 ( _attr : TokenStream , item : TokenStream ) -> TokenStream {
98+ let input = parse_macro_input ! ( item as ItemFn ) ;
99+
100+ if input. sig . asyncness . is_none ( ) {
101+ return quote_spanned ! { input. sig. fn_token. span( ) =>
102+ compile_error!( "fn must be `async fn`" ) ;
103+ }
104+ . into ( ) ;
105+ }
106+
107+ if input. sig . ident != "main" {
108+ return quote_spanned ! { input. sig. ident. span( ) =>
109+ compile_error!( "only `async fn main` can be used for #[wstd::main]" ) ;
110+ }
111+ . into ( ) ;
112+ }
113+
114+ if !input. sig . inputs . is_empty ( ) {
115+ return quote_spanned ! { input. sig. inputs. span( ) =>
116+ compile_error!( "arguments to main are not supported" ) ;
117+ }
118+ . into ( ) ;
119+ }
120+ let attrs = input. attrs ;
121+ let output = input. sig . output ;
122+ let block = input. block ;
123+ let run_result = if returns_unit ( & output) {
124+ quote ! {
125+ __run( ) . await ;
126+ :: core:: result:: Result :: Ok ( ( ) )
127+ }
128+ } else {
129+ quote ! {
130+ :: core:: result:: Result :: map_err( __run( ) . await , |_| ( ) )
131+ }
132+ } ;
133+ quote ! {
134+ struct __WstdCliRunner;
135+
136+ impl :: wstd:: __internal:: wasip3:: exports:: cli:: run:: Guest for __WstdCliRunner {
137+ async fn run( ) -> :: core:: result:: Result <( ) , ( ) > {
138+ #( #attrs) *
139+ async fn __run( ) #output {
140+ #block
141+ }
142+
143+ #run_result
144+ }
145+ }
146+
147+ :: wstd:: __internal:: wasip3:: cli:: command:: export!(
148+ __WstdCliRunner with_types_in :: wstd:: __internal:: wasip3
149+ ) ;
150+
151+ // Provide a `main` so users don't have to write `#![no_main]`.
152+ fn main( ) {
153+ :: core:: unreachable!(
154+ "wstd p3 components run via the wasi:cli/run@0.3.0 export, not `main`"
155+ )
156+ }
157+ }
158+ . into ( )
159+ }
160+
161+ #[ proc_macro_attribute]
162+ pub fn attr_macro_test_p3 ( _attr : TokenStream , item : TokenStream ) -> TokenStream {
163+ let input = parse_macro_input ! ( item as ItemFn ) ;
164+
165+ if input. sig . asyncness . is_none ( ) {
166+ return quote_spanned ! { input. sig. fn_token. span( ) =>
167+ compile_error!( "fn must be `async fn`" ) ;
168+ }
169+ . into ( ) ;
170+ }
171+
172+ if !input. sig . inputs . is_empty ( ) {
173+ return quote_spanned ! { input. sig. inputs. span( ) =>
174+ compile_error!( "arguments to a test are not supported" ) ;
175+ }
176+ . into ( ) ;
177+ }
178+ let attrs = input. attrs ;
179+ let output = input. sig . output ;
180+ let block = input. block ;
181+ let name = input. sig . ident ;
182+ let message = format ! ( "test {name} ... " ) ;
183+ let run_result = if returns_unit ( & output) {
184+ quote ! {
185+ :: std:: println!( "" ) ;
186+ :: std:: print!( #message) ;
187+ __run( ) . await ;
188+ :: std:: println!( "ok" ) ;
189+ :: std:: println!( "" ) ;
190+ :: core:: result:: Result :: Ok ( ( ) )
191+ }
192+ } else {
193+ quote ! {
194+ :: std:: println!( "" ) ;
195+ :: std:: print!( #message) ;
196+ match __run( ) . await {
197+ :: core:: result:: Result :: Ok ( _) => {
198+ :: std:: println!( "ok" ) ;
199+ :: std:: println!( "" ) ;
200+ :: core:: result:: Result :: Ok ( ( ) )
201+ }
202+ :: core:: result:: Result :: Err ( err) => {
203+ :: std:: println!( "failed" ) ;
204+ :: std:: println!( "Error {:?}" , err) ;
205+ :: std:: println!( "" ) ;
206+ :: core:: result:: Result :: Err ( ( ) )
207+ }
208+ }
209+ }
210+ } ;
211+ quote ! {
212+ struct __WstdCliRunner;
213+
214+ impl :: wstd:: __internal:: wasip3:: exports:: cli:: run:: Guest for __WstdCliRunner {
215+ async fn run( ) -> :: core:: result:: Result <( ) , ( ) > {
216+ #( #attrs) *
217+ async fn __run( ) #output {
218+ #block
219+ }
220+
221+ #run_result
222+ }
223+ }
224+
225+ :: wstd:: __internal:: wasip3:: cli:: command:: export!(
226+ __WstdCliRunner with_types_in :: wstd:: __internal:: wasip3
227+ ) ;
228+
229+ // Provide a `main` so users don't have to write `#![no_main]`.
230+ fn main( ) {
231+ :: core:: unreachable!(
232+ "wstd p3 components run via the wasi:cli/run@0.3.0 export, not `main`"
233+ )
234+ }
235+ }
236+ . into ( )
237+ }
238+
87239/// Enables a HTTP server main function, for creating [HTTP servers].
88240///
89241/// [HTTP servers]: https://docs.rs/wstd/latest/wstd/http/server/index.html
0 commit comments