@@ -26,6 +26,8 @@ enum SelfKind {
2626enum RefKind {
2727 Ref ,
2828 Mut ,
29+ OptionRef ,
30+ OptionMut ,
2931}
3032
3133struct ArgInfo {
@@ -104,6 +106,25 @@ fn classify_ref_type(ty: &Type) -> Option<Type> {
104106 }
105107}
106108
109+ /// If `ty` is `Option<InnerType>`, return the inner type.
110+ fn try_unwrap_option ( ty : & Type ) -> Option < & Type > {
111+ let Type :: Path ( type_path) = ty else { return None } ;
112+ let segment = type_path. path . segments . last ( ) ?;
113+ if segment. ident != "Option" {
114+ return None ;
115+ }
116+ let syn:: PathArguments :: AngleBracketed ( args) = & segment. arguments else {
117+ return None ;
118+ } ;
119+ if args. args . len ( ) != 1 {
120+ return None ;
121+ }
122+ let syn:: GenericArgument :: Type ( inner) = & args. args [ 0 ] else {
123+ return None ;
124+ } ;
125+ Some ( inner)
126+ }
127+
107128/// Analyze method signature.
108129///
109130/// Determine `self` kind and collect the callback arguments.
@@ -134,12 +155,32 @@ fn analyze_self_and_args(sig: &Signature) -> syn::Result<MethodInfo> {
134155 check_first_typed = false ;
135156 if let syn:: Pat :: Ident ( pat_ident) = & * typed. pat {
136157 let arg_type = & * typed. ty ;
158+ let mut option_inner = None ;
137159 let ref_kind = match arg_type {
138160 Type :: Reference ( r) if r. mutability . is_some ( ) => Some ( RefKind :: Mut ) ,
139161 Type :: Reference ( _) => Some ( RefKind :: Ref ) ,
140- _ => None ,
162+ _ => {
163+ // Check if it's `Option<&T>` or `Option<&mut T>`
164+ option_inner = try_unwrap_option ( arg_type) ;
165+ option_inner. and_then ( |inner| match inner {
166+ Type :: Reference ( r) if r. mutability . is_some ( ) => Some ( RefKind :: OptionMut ) ,
167+ Type :: Reference ( _) => Some ( RefKind :: OptionRef ) ,
168+ _ => None ,
169+ } )
170+ }
141171 } ;
142172 let callback_type = match & ref_kind {
173+ Some ( RefKind :: OptionRef | RefKind :: OptionMut ) => {
174+ match classify_ref_type ( option_inner. unwrap ( ) ) {
175+ Some ( ty) => parse_quote ! { Option <#ty> } ,
176+ None => {
177+ return Err ( syn:: Error :: new_spanned (
178+ arg_type,
179+ "this reference type is not supported as a callback parameter" ,
180+ ) ) ;
181+ }
182+ }
183+ }
143184 Some ( _) => match classify_ref_type ( arg_type) {
144185 Some ( ty) => ty,
145186 None => {
@@ -449,7 +490,7 @@ fn gen_closure_destructure(info: &MethodInfo) -> TokenStream2 {
449490 . iter ( )
450491 . map ( |a| {
451492 let ident = & a. ident ;
452- if matches ! ( a. userdata_ref, Some ( RefKind :: Mut ) ) {
493+ if matches ! ( a. userdata_ref, Some ( RefKind :: Mut | RefKind :: OptionMut ) ) {
453494 quote ! { mut #ident }
454495 } else {
455496 quote ! { #ident }
@@ -460,6 +501,18 @@ fn gen_closure_destructure(info: &MethodInfo) -> TokenStream2 {
460501 quote ! { ( #( #idents) , * ) : ( #( #types) , * ) }
461502}
462503
504+ /// Generate the call-site expression for a single argument.
505+ fn gen_arg_token ( arg : & ArgInfo ) -> TokenStream2 {
506+ let ident = & arg. ident ;
507+ match arg. userdata_ref {
508+ Some ( RefKind :: Ref ) => quote ! { & * #ident } ,
509+ Some ( RefKind :: Mut ) => quote ! { & mut * #ident } ,
510+ Some ( RefKind :: OptionRef ) => quote ! { #ident. as_ref( ) . map( |r| & * * r) } ,
511+ Some ( RefKind :: OptionMut ) => quote ! { #ident. as_mut( ) . map( |r| & mut * * r) } ,
512+ None => quote ! { #ident } ,
513+ }
514+ }
515+
463516/// Generate call arguments for invoking the original method.
464517fn gen_call_args ( info : & MethodInfo ) -> TokenStream2 {
465518 let mut call_args: Vec < TokenStream2 > = Vec :: new ( ) ;
@@ -474,12 +527,7 @@ fn gen_call_args(info: &MethodInfo) -> TokenStream2 {
474527 }
475528
476529 for arg in & info. args {
477- let ident = & arg. ident ;
478- match arg. userdata_ref {
479- Some ( RefKind :: Ref ) => call_args. push ( quote ! { & * #ident } ) ,
480- Some ( RefKind :: Mut ) => call_args. push ( quote ! { & mut * #ident } ) ,
481- None => call_args. push ( quote ! { #ident } ) ,
482- }
530+ call_args. push ( gen_arg_token ( arg) ) ;
483531 }
484532
485533 quote ! { #( #call_args) , * }
@@ -491,8 +539,8 @@ fn gen_async_call_args(info: &MethodInfo) -> TokenStream2 {
491539
492540 match info. self_kind {
493541 SelfKind :: None => { }
494- SelfKind :: Ref ( RefKind :: Ref ) => call_args. push ( quote ! { & this } ) ,
495- SelfKind :: Ref ( RefKind :: Mut ) => call_args. push ( quote ! { & mut this } ) ,
542+ SelfKind :: Ref ( RefKind :: Mut | RefKind :: OptionMut ) => call_args. push ( quote ! { & mut this } ) ,
543+ SelfKind :: Ref ( _ ) => call_args. push ( quote ! { & this } ) ,
496544 SelfKind :: Owned => call_args. push ( quote ! { this } ) ,
497545 }
498546
@@ -501,12 +549,7 @@ fn gen_async_call_args(info: &MethodInfo) -> TokenStream2 {
501549 }
502550
503551 for arg in & info. args {
504- let ident = & arg. ident ;
505- match arg. userdata_ref {
506- Some ( RefKind :: Ref ) => call_args. push ( quote ! { & * #ident } ) ,
507- Some ( RefKind :: Mut ) => call_args. push ( quote ! { & mut * #ident } ) ,
508- None => call_args. push ( quote ! { #ident } ) ,
509- }
552+ call_args. push ( gen_arg_token ( arg) ) ;
510553 }
511554
512555 quote ! { #( #call_args) , * }
@@ -640,12 +683,12 @@ fn gen_regular_method(
640683 quote ! { #fn_path( #call_args) }
641684 } ;
642685 match info. self_kind {
643- SelfKind :: Ref ( RefKind :: Ref ) => quote ! {
644- registry. add_method( #lua_name, #closure_params { #body } ) ;
645- } ,
646- SelfKind :: Ref ( RefKind :: Mut ) => quote ! {
686+ SelfKind :: Ref ( RefKind :: Mut | RefKind :: OptionMut ) => quote ! {
647687 registry. add_method_mut( #lua_name, #closure_params { #body } ) ;
648688 } ,
689+ SelfKind :: Ref ( _) => quote ! {
690+ registry. add_method( #lua_name, #closure_params { #body } ) ;
691+ } ,
649692 SelfKind :: Owned => quote ! {
650693 registry. add_method_once( #lua_name, #closure_params { #body } ) ;
651694 } ,
@@ -672,12 +715,12 @@ fn gen_async_regular_method(
672715 quote ! { async move { #fn_path( #call_args) . await } }
673716 } ;
674717 match info. self_kind {
675- SelfKind :: Ref ( RefKind :: Ref ) => quote ! {
676- registry. add_async_method( #lua_name, #closure_params #body) ;
677- } ,
678- SelfKind :: Ref ( RefKind :: Mut ) => quote ! {
718+ SelfKind :: Ref ( RefKind :: Mut | RefKind :: OptionMut ) => quote ! {
679719 registry. add_async_method_mut( #lua_name, #closure_params #body) ;
680720 } ,
721+ SelfKind :: Ref ( _) => quote ! {
722+ registry. add_async_method( #lua_name, #closure_params #body) ;
723+ } ,
681724 SelfKind :: Owned => quote ! {
682725 registry. add_async_method_once( #lua_name, #closure_params #body) ;
683726 } ,
0 commit comments