@@ -589,36 +589,39 @@ macro_rules! impl_script_function {
589
589
590
590
$( let $context = caller_context; ) ?
591
591
let world = caller_context. world( ) ?;
592
- world. begin_access_scope( ) ?;
593
- let mut current_arg = 0 ;
594
-
595
- $(
596
- current_arg += 1 ;
597
- let $param = args. pop_front( ) ;
598
- let $param = match $param {
599
- Some ( $param) => $param,
600
- None => {
601
- if let Some ( default ) = <$param>:: default_value( ) {
602
- default
603
- } else {
604
- return Err ( InteropError :: argument_count_mismatch( expected_arg_count, received_args_len) ) ;
605
- }
606
- }
607
- } ;
608
- let $param = <$param>:: from_script( $param, world. clone( ) )
609
- . map_err( |e| InteropError :: function_arg_conversion_error( current_arg. to_string( ) , e) ) ?;
610
- ) *
611
-
612
- let ret = {
613
- let out = self ( $( $context, ) ? $( $param. into( ) , ) * ) ;
614
- $(
615
- let $out = out?;
616
- let out = $out;
617
- ) ?
618
- out. into_script( world. clone( ) ) . map_err( |e| InteropError :: function_arg_conversion_error( "return value" . to_owned( ) , e) )
592
+ // Safety: we're not holding any references to the world, the arguments which might have aliased will always be dropped
593
+ let ret: Result <ScriptValue , InteropError > = unsafe {
594
+ world. with_access_scope( ||{
595
+ let mut current_arg = 0 ;
596
+
597
+ $(
598
+ current_arg += 1 ;
599
+ let $param = args. pop_front( ) ;
600
+ let $param = match $param {
601
+ Some ( $param) => $param,
602
+ None => {
603
+ if let Some ( default ) = <$param>:: default_value( ) {
604
+ default
605
+ } else {
606
+ return Err ( InteropError :: argument_count_mismatch( expected_arg_count, received_args_len) ) ;
607
+ }
608
+ }
609
+ } ;
610
+ let $param = <$param>:: from_script( $param, world. clone( ) )
611
+ . map_err( |e| InteropError :: function_arg_conversion_error( current_arg. to_string( ) , e) ) ?;
612
+ ) *
613
+
614
+ let ret = {
615
+ let out = self ( $( $context, ) ? $( $param. into( ) , ) * ) ;
616
+ $(
617
+ let $out = out?;
618
+ let out = $out;
619
+ ) ?
620
+ out. into_script( world. clone( ) ) . map_err( |e| InteropError :: function_arg_conversion_error( "return value" . to_owned( ) , e) )
621
+ } ;
622
+ ret
623
+ } ) ?
619
624
} ;
620
- // Safety: we're not holding any references to the world, the arguments which might have aliased have been dropped
621
- unsafe { world. end_access_scope( ) ? } ;
622
625
ret
623
626
} ) ( ) ;
624
627
let script_value: ScriptValue = res. into( ) ;
@@ -695,6 +698,25 @@ mod test {
695
698
} ) ;
696
699
}
697
700
701
+ #[ test]
702
+ fn test_interrupted_call_releases_access_scope ( ) {
703
+ #[ derive( bevy:: prelude:: Component , Reflect ) ]
704
+ struct Comp ;
705
+
706
+ let fn_ = |_a : crate :: bindings:: function:: from:: Mut < Comp > | 0usize ;
707
+ let script_function = fn_. into_dynamic_script_function ( ) . with_name ( "my_fn" ) ;
708
+
709
+ with_local_world ( || {
710
+ let out =
711
+ script_function. call ( vec ! [ ScriptValue :: from( 1 ) ] , FunctionCallContext :: default ( ) ) ;
712
+
713
+ assert ! ( out. is_err( ) ) ;
714
+ let world = FunctionCallContext :: default ( ) . world ( ) . unwrap ( ) ;
715
+ // assert no access is held
716
+ assert ! ( world. list_accesses( ) . is_empty( ) ) ;
717
+ } ) ;
718
+ }
719
+
698
720
#[ test]
699
721
fn test_overloaded_script_function ( ) {
700
722
let mut registry = ScriptFunctionRegistry :: default ( ) ;
0 commit comments