55 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
66 */
77
8+ use std:: thread:: ThreadId ;
89use std:: { fmt, ptr} ;
910
1011use godot_ffi as sys;
@@ -162,16 +163,7 @@ impl Callable {
162163 F : ' static + FnMut ( & [ & Variant ] ) -> R ,
163164 S : meta:: AsArg < GString > ,
164165 {
165- #[ cfg( debug_assertions) ]
166- meta:: arg_into_owned!( name) ;
167-
168- Self :: from_fn_wrapper :: < F , R > ( FnWrapper {
169- rust_function,
170- #[ cfg( debug_assertions) ]
171- name,
172- thread_id : Some ( std:: thread:: current ( ) . id ( ) ) ,
173- linked_obj_id : None ,
174- } )
166+ Self :: from_fn_wrapper ( name, rust_function, Some ( std:: thread:: current ( ) . id ( ) ) , None )
175167 }
176168
177169 /// Creates a new callable linked to the given object from **single-threaded** Rust function or closure.
@@ -189,16 +181,12 @@ impl Callable {
189181 F : ' static + FnMut ( & [ & Variant ] ) -> R ,
190182 S : meta:: AsArg < GString > ,
191183 {
192- #[ cfg( debug_assertions) ]
193- meta:: arg_into_owned!( name) ;
194-
195- Self :: from_fn_wrapper :: < F , R > ( FnWrapper {
196- rust_function,
197- #[ cfg( debug_assertions) ]
184+ Self :: from_fn_wrapper (
198185 name,
199- thread_id : Some ( std:: thread:: current ( ) . id ( ) ) ,
200- linked_obj_id : Some ( linked_object. instance_id ( ) ) ,
201- } )
186+ rust_function,
187+ Some ( std:: thread:: current ( ) . id ( ) ) ,
188+ Some ( linked_object. instance_id ( ) ) ,
189+ )
202190 }
203191
204192 /// This constructor is being phased out in favor of [`from_fn()`][Self::from_fn], but kept through v0.4 for smoother migration.
@@ -258,16 +246,8 @@ impl Callable {
258246 F : FnMut ( & [ & Variant ] ) -> Variant ,
259247 Fc : FnOnce ( & Callable ) -> R ,
260248 {
261- #[ cfg( debug_assertions) ]
262- meta:: arg_into_owned!( name) ;
263-
264- let callable = Self :: from_fn_wrapper :: < F , Variant > ( FnWrapper {
265- rust_function,
266- #[ cfg( debug_assertions) ]
267- name,
268- thread_id : Some ( std:: thread:: current ( ) . id ( ) ) ,
269- linked_obj_id : None ,
270- } ) ;
249+ let callable =
250+ Self :: from_fn_wrapper ( name, rust_function, Some ( std:: thread:: current ( ) . id ( ) ) , None ) ;
271251
272252 callable_usage ( & callable)
273253 }
@@ -298,16 +278,7 @@ impl Callable {
298278 F : ' static + Send + Sync + FnMut ( & [ & Variant ] ) -> R ,
299279 S : meta:: AsArg < GString > ,
300280 {
301- #[ cfg( debug_assertions) ]
302- meta:: arg_into_owned!( name) ;
303-
304- Self :: from_fn_wrapper :: < F , R > ( FnWrapper {
305- rust_function,
306- #[ cfg( debug_assertions) ]
307- name,
308- thread_id : None ,
309- linked_obj_id : None ,
310- } )
281+ Self :: from_fn_wrapper ( name, rust_function, None , None )
311282 }
312283
313284 /// Create a highly configurable callable from Rust.
@@ -334,21 +305,37 @@ impl Callable {
334305 Self :: from_custom_info ( info)
335306 }
336307
337- fn from_fn_wrapper < F , R > ( inner : FnWrapper < F > ) -> Self
308+ fn from_fn_wrapper < F , R , S > (
309+ _name : S ,
310+ rust_function : F ,
311+ thread_id : Option < ThreadId > ,
312+ linked_obj_id : Option < InstanceId > ,
313+ ) -> Self
338314 where
339315 F : FnMut ( & [ & Variant ] ) -> R ,
340316 R : ToGodot ,
317+ S : meta:: AsArg < GString > ,
341318 {
342- let object_id = inner. linked_object_id ( ) ;
319+ #[ cfg( safeguards_balanced) ]
320+ meta:: arg_into_owned!( _name) ;
321+
322+ let wrapper = FnWrapper {
323+ rust_function,
324+ #[ cfg( safeguards_balanced) ]
325+ name : _name,
326+ thread_id,
327+ linked_obj_id,
328+ } ;
343329
344- let userdata = CallableUserdata { inner } ;
330+ let object_id = wrapper. linked_object_id ( ) ;
331+ let userdata = CallableUserdata { inner : wrapper } ;
345332
346333 let info = CallableCustomInfo {
347334 object_id,
348335 callable_userdata : Box :: into_raw ( Box :: new ( userdata) ) as * mut std:: ffi:: c_void ,
349336 call_func : Some ( rust_callable_call_fn :: < F , R > ) ,
350337 free_func : Some ( rust_callable_destroy :: < FnWrapper < F > > ) ,
351- #[ cfg( debug_assertions ) ]
338+ #[ cfg( safeguards_balanced ) ]
352339 to_string_func : Some ( rust_callable_to_string_named :: < F > ) ,
353340 is_valid_func : Some ( rust_callable_is_valid) ,
354341 ..Self :: default_callable_custom_info ( )
@@ -617,7 +604,7 @@ mod custom_callable {
617604
618605 pub ( crate ) struct FnWrapper < F > {
619606 pub ( super ) rust_function : F ,
620- #[ cfg( debug_assertions ) ]
607+ #[ cfg( safeguards_balanced ) ]
621608 pub ( super ) name : GString ,
622609
623610 /// `None` if the callable is multi-threaded ([`Callable::from_sync_fn`]).
@@ -668,12 +655,12 @@ mod custom_callable {
668655 ) {
669656 let arg_refs: & [ & Variant ] = Variant :: borrow_ref_slice ( p_args, p_argument_count as usize ) ;
670657
671- #[ cfg( debug_assertions ) ]
658+ #[ cfg( safeguards_balanced ) ]
672659 let name = & {
673660 let c: & C = CallableUserdata :: inner_from_raw ( callable_userdata) ;
674661 c. to_string ( )
675662 } ;
676- #[ cfg( not( debug_assertions ) ) ]
663+ #[ cfg( not( safeguards_balanced ) ) ]
677664 let name = "<optimized out>" ;
678665 let ctx = meta:: CallContext :: custom_callable ( name) ;
679666
@@ -698,34 +685,31 @@ mod custom_callable {
698685 {
699686 let arg_refs: & [ & Variant ] = Variant :: borrow_ref_slice ( p_args, p_argument_count as usize ) ;
700687
701- #[ cfg( debug_assertions ) ]
688+ #[ cfg( safeguards_balanced ) ]
702689 let name = & {
703690 let w: & FnWrapper < F > = CallableUserdata :: inner_from_raw ( callable_userdata) ;
704691 w. name . to_string ( )
705692 } ;
706- #[ cfg( not( debug_assertions ) ) ]
693+ #[ cfg( not( safeguards_balanced ) ) ]
707694 let name = "<optimized out>" ;
708695 let ctx = meta:: CallContext :: custom_callable ( name) ;
709696
710697 crate :: private:: handle_fallible_varcall ( & ctx, & mut * r_error, move || {
711698 // Get the FnWrapper again inside closure so the FnMut doesn't have to be UnwindSafe.
712699 let w: & mut FnWrapper < F > = CallableUserdata :: inner_from_raw ( callable_userdata) ;
713700
714- if w. thread_id
715- . is_some_and ( |tid| tid != std:: thread:: current ( ) . id ( ) )
716- {
717- #[ cfg( debug_assertions) ]
718- let name = & w. name ;
719- #[ cfg( not( debug_assertions) ) ]
720- let name = "<optimized out>" ;
721- // NOTE: this panic is currently not propagated to the caller, but results in an error message and Nil return.
722- // See comments in itest callable_call() for details.
723- panic ! (
724- "Callable '{}' created with from_fn() must be called from the same thread it was created in.\n \
725- If you need to call it from any thread, use from_sync_fn() instead (requires `experimental-threads` feature).",
726- name
727- ) ;
728- }
701+ #[ cfg( safeguards_balanced) ]
702+ let name = & w. name ;
703+ #[ cfg( not( safeguards_balanced) ) ]
704+ let name = "<optimized out>" ;
705+
706+ // NOTE: this panic is currently not propagated to the caller, but results in an error message and Nil return.
707+ // See comments in itest callable_call() for details.
708+ sys:: balanced_assert!(
709+ w. thread_id. is_none( ) || w. thread_id == Some ( std:: thread:: current( ) . id( ) ) ,
710+ "Callable '{name}' created with from_fn() must be called from the same thread it was created in.\n \
711+ If you need to call it from any thread, use from_sync_fn() instead (requires `experimental-threads` feature)."
712+ ) ;
729713
730714 let result = ( w. rust_function ) ( arg_refs) . to_variant ( ) ;
731715 meta:: varcall_return_checked ( Ok ( result) , r_return, r_error) ;
@@ -769,7 +753,7 @@ mod custom_callable {
769753 * r_is_valid = sys:: conv:: SYS_TRUE ;
770754 }
771755
772- #[ cfg( debug_assertions ) ]
756+ #[ cfg( safeguards_balanced ) ]
773757 pub unsafe extern "C" fn rust_callable_to_string_named < F > (
774758 callable_userdata : * mut std:: ffi:: c_void ,
775759 r_is_valid : * mut sys:: GDExtensionBool ,
0 commit comments