@@ -8,6 +8,7 @@ use syn::{
88} ;
99
1010use super :: attr:: LuaAttr ;
11+ use super :: with_cfg;
1112
1213/// `&T` reference types that mlua provides as wrapper types via `FromLua`.
1314static BORROW_WRAPPERS : & [ ( & str , & str ) ] = & [
@@ -235,13 +236,15 @@ pub fn userdata_impl(attr: TokenStream, item: TokenStream) -> TokenStream {
235236 let const_name = & const_item. ident ;
236237 let lua_name = lua_attr. name ( const_name) ;
237238 if lua_attr. meta {
238- registration_calls . push ( quote ! {
239+ let tokens = quote ! {
239240 registry. add_meta_field( #lua_name, #type_path:: #const_name) ;
240- } ) ;
241+ } ;
242+ registration_calls. push ( with_cfg ( tokens, & const_item. attrs ) ) ;
241243 } else {
242- registration_calls . push ( quote ! {
244+ let tokens = quote ! {
243245 registry. add_field( #lua_name, #type_path:: #const_name) ;
244- } ) ;
246+ } ;
247+ registration_calls. push ( with_cfg ( tokens, & const_item. attrs ) ) ;
245248 }
246249 }
247250 ImplItem :: Fn ( method) => {
@@ -273,8 +276,14 @@ pub fn userdata_impl(attr: TokenStream, item: TokenStream) -> TokenStream {
273276
274277 let fn_name = & method. sig . ident ;
275278 let info = try_compile ! ( analyze_self_and_args( & method. sig) ) ;
279+ let is_async = method. sig . asyncness . is_some ( ) ;
276280
277281 if lua_attr. getter {
282+ if is_async {
283+ return syn:: Error :: new_spanned ( & method. sig , "async field getter is not supported" )
284+ . to_compile_error ( )
285+ . into ( ) ;
286+ }
278287 if !matches ! ( info. self_kind, SelfKind :: Ref ( RefKind :: Ref ) ) {
279288 return syn:: Error :: new_spanned ( & method. sig , "field getter must take `&self`" )
280289 . to_compile_error ( )
@@ -288,10 +297,16 @@ pub fn userdata_impl(attr: TokenStream, item: TokenStream) -> TokenStream {
288297 . to_compile_error ( )
289298 . into ( ) ;
290299 }
291- registration_calls. push ( gen_field_getter ( type_path, fn_name, & lua_attr, & info) ) ;
300+ let tokens = gen_field_getter ( type_path, fn_name, & lua_attr, & info) ;
301+ registration_calls. push ( with_cfg ( tokens, & method. attrs ) ) ;
292302 continue ;
293303 }
294304 if lua_attr. setter {
305+ if is_async {
306+ return syn:: Error :: new_spanned ( & method. sig , "async field setter is not supported" )
307+ . to_compile_error ( )
308+ . into ( ) ;
309+ }
295310 if !matches ! ( info. self_kind, SelfKind :: Ref ( _) ) {
296311 return syn:: Error :: new_spanned ( & method. sig , "field setter must take `&[mut] self`" )
297312 . to_compile_error ( )
@@ -305,24 +320,32 @@ pub fn userdata_impl(attr: TokenStream, item: TokenStream) -> TokenStream {
305320 . to_compile_error ( )
306321 . into ( ) ;
307322 }
308- registration_calls. push ( gen_field_setter ( type_path, fn_name, & lua_attr, & info) ) ;
323+ let tokens = gen_field_setter ( type_path, fn_name, & lua_attr, & info) ;
324+ registration_calls. push ( with_cfg ( tokens, & method. attrs ) ) ;
309325 continue ;
310326 }
311327 if lua_attr. field {
328+ if is_async {
329+ return syn:: Error :: new_spanned ( & method. sig , "async field function is not supported" )
330+ . to_compile_error ( )
331+ . into ( ) ;
332+ }
312333 if !matches ! ( info. self_kind, SelfKind :: None ) {
313334 return syn:: Error :: new_spanned ( & method. sig , "field function must not take `self`" )
314335 . to_compile_error ( )
315336 . into ( ) ;
316337 }
317338 let lua_name = lua_attr. name ( fn_name) ;
318339 if lua_attr. meta {
319- registration_calls. push ( quote ! {
320- registry. add_meta_field( #lua_name, #type_path:: #fn_name( ) ) ;
321- } ) ;
340+ let tokens = quote ! {
341+ registry. add_meta_field( #lua_name, #type_path:: #fn_name) ;
342+ } ;
343+ registration_calls. push ( with_cfg ( tokens, & method. attrs ) ) ;
322344 } else {
323- registration_calls . push ( quote ! {
345+ let tokens = quote ! {
324346 registry. add_field( #lua_name, #type_path:: #fn_name( ) ) ;
325- } ) ;
347+ } ;
348+ registration_calls. push ( with_cfg ( tokens, & method. attrs ) ) ;
326349 }
327350 continue ;
328351 }
@@ -336,11 +359,23 @@ pub fn userdata_impl(attr: TokenStream, item: TokenStream) -> TokenStream {
336359 . to_compile_error ( )
337360 . into ( ) ;
338361 }
339- registration_calls. push ( gen_meta ( type_path, fn_name, & lua_attr, & info) ) ;
362+ if is_async {
363+ let tokens = gen_async_meta ( type_path, fn_name, & lua_attr, & info) ;
364+ registration_calls. push ( with_cfg ( tokens, & method. attrs ) ) ;
365+ } else {
366+ let tokens = gen_meta ( type_path, fn_name, & lua_attr, & info) ;
367+ registration_calls. push ( with_cfg ( tokens, & method. attrs ) ) ;
368+ }
340369 continue ;
341370 }
342371
343- registration_calls. push ( gen_regular_method ( type_path, fn_name, & lua_attr, & info) ) ;
372+ if is_async {
373+ let tokens = gen_async_regular_method ( type_path, fn_name, & lua_attr, & info) ;
374+ registration_calls. push ( with_cfg ( tokens, & method. attrs ) ) ;
375+ } else {
376+ let tokens = gen_regular_method ( type_path, fn_name, & lua_attr, & info) ;
377+ registration_calls. push ( with_cfg ( tokens, & method. attrs ) ) ;
378+ }
344379 }
345380 _ => { }
346381 }
@@ -417,6 +452,33 @@ fn gen_call_args(info: &MethodInfo) -> TokenStream2 {
417452 quote ! { #( #call_args) , * }
418453}
419454
455+ /// Generate call arguments for invoking the original async method.
456+ fn gen_async_call_args ( info : & MethodInfo ) -> TokenStream2 {
457+ let mut call_args: Vec < TokenStream2 > = Vec :: new ( ) ;
458+
459+ match info. self_kind {
460+ SelfKind :: None => { }
461+ SelfKind :: Ref ( RefKind :: Ref ) => call_args. push ( quote ! { & this } ) ,
462+ SelfKind :: Ref ( RefKind :: Mut ) => call_args. push ( quote ! { & mut this } ) ,
463+ SelfKind :: Owned => call_args. push ( quote ! { this } ) ,
464+ }
465+
466+ if info. has_lua {
467+ call_args. push ( quote ! { lua } ) ;
468+ }
469+
470+ for arg in & info. args {
471+ let ident = & arg. ident ;
472+ match arg. userdata_ref {
473+ Some ( RefKind :: Ref ) => call_args. push ( quote ! { & * #ident } ) ,
474+ Some ( RefKind :: Mut ) => call_args. push ( quote ! { & mut * #ident } ) ,
475+ None => call_args. push ( quote ! { #ident } ) ,
476+ }
477+ }
478+
479+ quote ! { #( #call_args) , * }
480+ }
481+
420482/// Generate the closure params for the registration callback.
421483fn gen_closure_params ( info : & MethodInfo ) -> TokenStream2 {
422484 let destructure = gen_closure_destructure ( info) ;
@@ -426,6 +488,16 @@ fn gen_closure_params(info: &MethodInfo) -> TokenStream2 {
426488 }
427489}
428490
491+ /// Generate the closure params for an async registration callback.
492+ fn gen_async_closure_params ( info : & MethodInfo ) -> TokenStream2 {
493+ let destructure = gen_closure_destructure ( info) ;
494+ match info. self_kind {
495+ SelfKind :: None => quote ! { |lua, #destructure| } ,
496+ SelfKind :: Ref ( RefKind :: Mut ) => quote ! { |lua, mut this, #destructure| } ,
497+ _ => quote ! { |lua, this, #destructure| } ,
498+ }
499+ }
500+
429501fn gen_field_getter (
430502 type_path : & syn:: Path ,
431503 fn_name : & Ident ,
@@ -549,3 +621,77 @@ fn gen_regular_method(
549621 } ,
550622 }
551623}
624+
625+ fn gen_async_regular_method (
626+ type_path : & syn:: Path ,
627+ fn_name : & Ident ,
628+ lua_attr : & LuaAttr ,
629+ info : & MethodInfo ,
630+ ) -> TokenStream2 {
631+ let fn_path = quote ! { #type_path:: #fn_name } ;
632+ let closure_params = gen_async_closure_params ( info) ;
633+ let call_args = gen_async_call_args ( info) ;
634+ let lua_name = lua_attr. name ( fn_name) ;
635+
636+ let body = if lua_attr. infallible {
637+ quote ! { async move { Ok ( #fn_path( #call_args) . await ) } }
638+ } else {
639+ quote ! { async move { #fn_path( #call_args) . await } }
640+ } ;
641+ match info. self_kind {
642+ SelfKind :: Ref ( RefKind :: Ref ) => quote ! {
643+ registry. add_async_method( #lua_name, #closure_params #body) ;
644+ } ,
645+ SelfKind :: Ref ( RefKind :: Mut ) => quote ! {
646+ registry. add_async_method_mut( #lua_name, #closure_params #body) ;
647+ } ,
648+ SelfKind :: Owned => quote ! {
649+ registry. add_async_method_once( #lua_name, #closure_params #body) ;
650+ } ,
651+ SelfKind :: None => quote ! {
652+ registry. add_async_function( #lua_name, #closure_params #body) ;
653+ } ,
654+ }
655+ }
656+
657+ fn gen_async_meta (
658+ type_path : & syn:: Path ,
659+ fn_name : & Ident ,
660+ lua_attr : & LuaAttr ,
661+ info : & MethodInfo ,
662+ ) -> TokenStream2 {
663+ let meta_name = match lua_attr. effective_meta_name ( fn_name) {
664+ Ok ( name) => name,
665+ Err ( err) => return err. to_compile_error ( ) ,
666+ } ;
667+ let closure_params = if matches ! ( info. self_kind, SelfKind :: None ) {
668+ if info. args . is_empty ( ) {
669+ quote ! { |lua, _this: :: mlua:: AnyUserData | }
670+ } else {
671+ let idents: Vec < _ > = info. args . iter ( ) . map ( |a| & a. ident ) . collect ( ) ;
672+ let types: Vec < _ > = info. args . iter ( ) . map ( |a| & a. callback_type ) . collect ( ) ;
673+ quote ! { |lua, ( _this, #( #idents) , * ) : ( :: mlua:: AnyUserData , #( #types) , * ) | }
674+ }
675+ } else {
676+ gen_async_closure_params ( info)
677+ } ;
678+ let call_args = gen_async_call_args ( info) ;
679+ let fn_path = quote ! { #type_path:: #fn_name } ;
680+
681+ let body = if lua_attr. infallible {
682+ quote ! { async move { Ok ( #fn_path( #call_args) . await ) } }
683+ } else {
684+ quote ! { async move { #fn_path( #call_args) . await } }
685+ } ;
686+ match info. self_kind {
687+ SelfKind :: None => quote ! {
688+ registry. add_async_meta_function( #meta_name, #closure_params #body) ;
689+ } ,
690+ SelfKind :: Ref ( RefKind :: Mut ) => quote ! {
691+ registry. add_async_meta_method_mut( #meta_name, #closure_params #body) ;
692+ } ,
693+ _ => quote ! {
694+ registry. add_async_meta_method( #meta_name, #closure_params #body) ;
695+ } ,
696+ }
697+ }
0 commit comments