6
6
*/
7
7
8
8
use std:: cell:: RefCell ;
9
+ use std:: collections:: HashMap ;
9
10
use std:: ffi:: c_void;
11
+ use std:: sync:: Mutex ;
10
12
11
13
use crate :: builtin:: meta:: { MethodInfo , PropertyInfo } ;
12
14
use crate :: builtin:: { GString , StringName , Variant , VariantType } ;
@@ -78,10 +80,10 @@ pub trait ScriptInstance {
78
80
fn get_property ( & self , name : StringName ) -> Option < Variant > ;
79
81
80
82
/// A list of all the properties a script exposes to the engine.
81
- fn get_property_list ( & self ) -> & [ PropertyInfo ] ;
83
+ fn get_property_list ( & self ) -> Vec < PropertyInfo > ;
82
84
83
85
/// A list of all the methods a script exposes to the engine.
84
- fn get_method_list ( & self ) -> & [ MethodInfo ] ;
86
+ fn get_method_list ( & self ) -> Vec < MethodInfo > ;
85
87
86
88
/// Method invoker for Godot's virtual dispatch system. The engine will call this function when it wants to call a method on the script.
87
89
///
@@ -150,11 +152,11 @@ impl<T: ScriptInstance + ?Sized> ScriptInstance for Box<T> {
150
152
self . as_ref ( ) . get_property ( name)
151
153
}
152
154
153
- fn get_property_list ( & self ) -> & [ PropertyInfo ] {
155
+ fn get_property_list ( & self ) -> Vec < PropertyInfo > {
154
156
self . as_ref ( ) . get_property_list ( )
155
157
}
156
158
157
- fn get_method_list ( & self ) -> & [ MethodInfo ] {
159
+ fn get_method_list ( & self ) -> Vec < MethodInfo > {
158
160
self . as_ref ( ) . get_method_list ( )
159
161
}
160
162
@@ -219,6 +221,8 @@ type ScriptInstanceInfo = sys::GDExtensionScriptInstanceInfo2;
219
221
struct ScriptInstanceData < T : ScriptInstance > {
220
222
inner : RefCell < T > ,
221
223
script_instance_ptr : * mut ScriptInstanceInfo ,
224
+ property_list : Mutex < HashMap < * const sys:: GDExtensionPropertyInfo , Vec < PropertyInfo > > > ,
225
+ method_list : Mutex < HashMap < * const sys:: GDExtensionMethodInfo , Vec < MethodInfo > > > ,
222
226
}
223
227
224
228
impl < T : ScriptInstance > Drop for ScriptInstanceData < T > {
@@ -290,6 +294,8 @@ pub fn create_script_instance<T: ScriptInstance>(rs_instance: T) -> *mut c_void
290
294
let data = ScriptInstanceData {
291
295
inner : RefCell :: new ( rs_instance) ,
292
296
script_instance_ptr : instance_ptr,
297
+ property_list : Default :: default ( ) ,
298
+ method_list : Default :: default ( ) ,
293
299
} ;
294
300
295
301
let data_ptr = Box :: into_raw ( Box :: new ( data) ) ;
@@ -382,13 +388,13 @@ mod script_instance_info {
382
388
/// # Safety
383
389
///
384
390
/// - The returned `*const T` is guaranteed to point to a list that has an equal length and capacity.
385
- fn transfer_ptr_list_to_godot < T > ( ptr_list : Vec < T > , list_length : & mut u32 ) -> * const T {
391
+ fn transfer_ptr_list_to_godot < T > ( ptr_list : Box < [ T ] > , list_length : & mut u32 ) -> * const T {
386
392
* list_length = ptr_list. len ( ) as u32 ;
387
393
388
- let ptr = Box :: into_raw ( ptr_list. into_boxed_slice ( ) ) ;
394
+ let ptr = Box :: into_raw ( ptr_list) ;
389
395
390
396
// SAFETY: `ptr` was just created in the line above and should be safe to dereference.
391
- unsafe { ( * ptr) . as_ptr ( ) }
397
+ unsafe { ( * ptr) . as_mut_ptr ( ) }
392
398
}
393
399
394
400
/// The returned pointer's lifetime is equal to the lifetime of `script`
@@ -505,23 +511,32 @@ mod script_instance_info {
505
511
) -> * const sys:: GDExtensionPropertyInfo {
506
512
let ctx = || format ! ( "error when calling {}::get_property_list" , type_name:: <T >( ) ) ;
507
513
508
- let property_list = handle_panic ( ctx, || {
514
+ let ( property_list, property_sys_list ) = handle_panic ( ctx, || {
509
515
let instance = instance_data_as_script_instance :: < T > ( p_instance) ;
510
516
511
- let property_list: Vec < _ > = borrow_instance ( instance)
512
- . get_property_list ( )
517
+ let property_list = borrow_instance ( instance) . get_property_list ( ) ;
518
+
519
+ let property_sys_list: Box < [ _ ] > = property_list
513
520
. iter ( )
514
521
. map ( |prop| prop. property_sys ( ) )
515
522
. collect ( ) ;
516
523
517
- property_list
524
+ ( property_list, property_sys_list )
518
525
} )
519
526
. unwrap_or_default ( ) ;
520
527
521
528
// SAFETY: list_length has to be a valid pointer to a u32.
522
529
let list_length = unsafe { & mut * r_count } ;
530
+ let return_pointer = transfer_ptr_list_to_godot ( property_sys_list, list_length) ;
531
+
532
+ let instance = instance_data_as_script_instance :: < T > ( p_instance) ;
533
+ instance
534
+ . property_list
535
+ . lock ( )
536
+ . expect ( "Mutex should not be poisoned" )
537
+ . insert ( return_pointer, property_list) ;
523
538
524
- transfer_ptr_list_to_godot ( property_list , list_length )
539
+ return_pointer
525
540
}
526
541
527
542
/// # Safety
@@ -534,23 +549,33 @@ mod script_instance_info {
534
549
) -> * const sys:: GDExtensionMethodInfo {
535
550
let ctx = || format ! ( "error when calling {}::get_method_list" , type_name:: <T >( ) ) ;
536
551
537
- let method_list = handle_panic ( ctx, || {
552
+ let ( method_list, method_sys_list ) = handle_panic ( ctx, || {
538
553
let instance = instance_data_as_script_instance :: < T > ( p_instance) ;
539
554
540
- let method_list: Vec < _ > = borrow_instance ( instance)
541
- . get_method_list ( )
555
+ let method_list = borrow_instance ( instance) . get_method_list ( ) ;
556
+
557
+ let method_sys_list = method_list
542
558
. iter ( )
543
559
. map ( |method| method. method_sys ( ) )
544
560
. collect ( ) ;
545
561
546
- method_list
562
+ ( method_list, method_sys_list )
547
563
} )
548
564
. unwrap_or_default ( ) ;
549
565
550
566
// SAFETY: list_length has to be a valid pointer to a u32.
551
567
let list_length = unsafe { & mut * r_count } ;
568
+ let return_pointer = transfer_ptr_list_to_godot ( method_sys_list, list_length) ;
569
+
570
+ let instance = instance_data_as_script_instance :: < T > ( p_instance) ;
552
571
553
- transfer_ptr_list_to_godot ( method_list, list_length)
572
+ instance
573
+ . method_list
574
+ . lock ( )
575
+ . expect ( "mutex should not be poisoned" )
576
+ . insert ( return_pointer, method_list) ;
577
+
578
+ return_pointer
554
579
}
555
580
556
581
/// # Safety
@@ -579,6 +604,16 @@ mod script_instance_info {
579
604
// and therefore should have the same length as before. get_propery_list_func
580
605
// also guarantees that both vector length and capacity are equal.
581
606
let _drop = transfer_ptr_list_from_godot ( p_prop_info, length) ;
607
+
608
+ // now drop the backing data
609
+ let instance = instance_data_as_script_instance :: < T > ( p_instance) ;
610
+
611
+ let _drop = instance
612
+ . property_list
613
+ . lock ( )
614
+ . expect ( "mutex should not be poisoned" )
615
+ . remove ( & p_prop_info)
616
+ . expect ( "we can not free a list that has not been allocated" ) ;
582
617
}
583
618
584
619
/// # Safety
0 commit comments