@@ -38,7 +38,7 @@ struct ArgInfo {
3838
3939struct MethodInfo {
4040 self_kind : SelfKind ,
41- has_lua : bool ,
41+ lua : Option < LuaArg > ,
4242 args : Vec < ArgInfo > ,
4343}
4444
@@ -50,18 +50,31 @@ fn ref_inner_type(ty: &Type) -> Type {
5050 }
5151}
5252
53- /// Check if the type is `&Lua` or `&mlua::Lua`.
54- fn is_lua_ref ( ty : & Type ) -> bool {
55- let Type :: Reference ( ref_ty) = ty else { return false } ;
56- match & * ref_ty. elem {
57- Type :: Path ( p) if p. path . segments . len ( ) == 1 => p. path . segments [ 0 ] . ident == "Lua" ,
58- Type :: Path ( p) if p. path . segments . len ( ) == 2 => {
59- p. path . segments [ 0 ] . ident == "mlua" && p. path . segments [ 1 ] . ident == "Lua"
60- }
53+ /// How the `Lua` context parameter is passed to the method.
54+ enum LuaArg {
55+ Ref ,
56+ Owned ,
57+ }
58+
59+ /// Check if the type is `Lua` or `mlua::Lua`.
60+ fn is_lua_type ( ty : & Type ) -> bool {
61+ let Type :: Path ( p) = ty else { return false } ;
62+ match p. path . segments . len ( ) {
63+ 1 => p. path . segments [ 0 ] . ident == "Lua" ,
64+ 2 => p. path . segments [ 0 ] . ident == "mlua" && p. path . segments [ 1 ] . ident == "Lua" ,
6165 _ => false ,
6266 }
6367}
6468
69+ /// Classify the method's `Lua` context parameter, if present.
70+ fn lua_arg_kind ( ty : & Type ) -> Option < LuaArg > {
71+ match ty {
72+ Type :: Reference ( r) if r. mutability . is_none ( ) && is_lua_type ( & r. elem ) => Some ( LuaArg :: Ref ) ,
73+ ty if is_lua_type ( ty) => Some ( LuaArg :: Owned ) ,
74+ _ => None ,
75+ }
76+ }
77+
6578/// Classify a `&[mut] T` parameter, returning the callback wrapper type.
6679///
6780/// Known borrow types come from the mapping table `BORROW_WRAPPERS`.
@@ -128,10 +141,10 @@ fn try_unwrap_option(ty: &Type) -> Option<&Type> {
128141/// Analyze method signature.
129142///
130143/// Determine `self` kind and collect the callback arguments.
131- /// Auto-detects `& Lua` as the first non-self parameter.
144+ /// Auto-detects `Lua` (owned or reference) as the first non-self parameter.
132145fn analyze_self_and_args ( sig : & Signature ) -> syn:: Result < MethodInfo > {
133146 let mut self_kind = SelfKind :: None ;
134- let mut has_lua = false ;
147+ let mut lua = None ;
135148 let mut args = Vec :: new ( ) ;
136149 let mut check_first_typed = true ;
137150
@@ -147,12 +160,14 @@ fn analyze_self_and_args(sig: &Signature) -> syn::Result<MethodInfo> {
147160 self_kind = SelfKind :: Owned ;
148161 }
149162 FnArg :: Typed ( typed) => {
150- if check_first_typed && is_lua_ref ( & typed. ty ) {
151- has_lua = true ;
163+ if check_first_typed {
152164 check_first_typed = false ;
153- continue ;
165+ if let Some ( kind) = lua_arg_kind ( & typed. ty ) {
166+ lua = Some ( kind) ;
167+ continue ;
168+ }
154169 }
155- check_first_typed = false ;
170+
156171 if let syn:: Pat :: Ident ( pat_ident) = & * typed. pat {
157172 let arg_type = & * typed. ty ;
158173 let mut option_inner = None ;
@@ -202,11 +217,7 @@ fn analyze_self_and_args(sig: &Signature) -> syn::Result<MethodInfo> {
202217 }
203218 }
204219
205- Ok ( MethodInfo {
206- self_kind,
207- has_lua,
208- args,
209- } )
220+ Ok ( MethodInfo { self_kind, lua, args } )
210221}
211222
212223fn strip_item_attrs ( attrs : & [ Attribute ] ) -> Vec < Attribute > {
@@ -343,6 +354,16 @@ pub fn userdata_impl(attr: TokenStream, item: TokenStream) -> TokenStream {
343354 let info = try_compile ! ( analyze_self_and_args( & method. sig) ) ;
344355 let is_async = method. sig . asyncness . is_some ( ) ;
345356
357+ // Owned `Lua` is only available to async callbacks.
358+ if !is_async && matches ! ( info. lua, Some ( LuaArg :: Owned ) ) {
359+ return syn:: Error :: new_spanned (
360+ & method. sig ,
361+ "owned `Lua` parameter is only supported for `async` methods (use `&Lua` instead)" ,
362+ )
363+ . to_compile_error ( )
364+ . into ( ) ;
365+ }
366+
346367 if lua_attr. getter {
347368 if is_async {
348369 return syn:: Error :: new_spanned ( & method. sig , "async field getter is not supported" )
@@ -520,7 +541,7 @@ fn gen_call_args(info: &MethodInfo) -> TokenStream2 {
520541 _ => call_args. push ( quote ! { this } ) ,
521542 }
522543
523- if info. has_lua {
544+ if info. lua . is_some ( ) {
524545 call_args. push ( quote ! { lua } ) ;
525546 }
526547
@@ -542,8 +563,10 @@ fn gen_async_call_args(info: &MethodInfo) -> TokenStream2 {
542563 SelfKind :: Owned => call_args. push ( quote ! { this } ) ,
543564 }
544565
545- if info. has_lua {
546- call_args. push ( quote ! { lua } ) ;
566+ match info. lua {
567+ Some ( LuaArg :: Ref ) => call_args. push ( quote ! { & lua } ) ,
568+ Some ( LuaArg :: Owned ) => call_args. push ( quote ! { lua } ) ,
569+ None => { }
547570 }
548571
549572 for arg in & info. args {
0 commit comments