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) ) ;
@@ -364,13 +370,13 @@ mod script_instance_info {
364
370
/// # Safety
365
371
///
366
372
/// - The returned `*const T` is guaranteed to point to a list that has an equal length and capacity.
367
- fn transfer_ptr_list_to_godot < T > ( ptr_list : Vec < T > , list_length : & mut u32 ) -> * const T {
373
+ fn transfer_ptr_list_to_godot < T > ( ptr_list : Box < [ T ] > , list_length : & mut u32 ) -> * mut T {
368
374
* list_length = ptr_list. len ( ) as u32 ;
369
375
370
- let ptr = Box :: into_raw ( ptr_list. into_boxed_slice ( ) ) ;
376
+ let ptr = Box :: into_raw ( ptr_list) ;
371
377
372
378
// SAFETY: `ptr` was just created in the line above and should be safe to dereference.
373
- unsafe { ( * ptr) . as_ptr ( ) }
379
+ unsafe { ( * ptr) . as_mut_ptr ( ) }
374
380
}
375
381
376
382
/// The returned pointer's lifetime is equal to the lifetime of `script`
@@ -487,23 +493,32 @@ mod script_instance_info {
487
493
) -> * const sys:: GDExtensionPropertyInfo {
488
494
let ctx = || format ! ( "error when calling {}::get_property_list" , type_name:: <T >( ) ) ;
489
495
490
- let property_list = handle_panic ( ctx, || {
496
+ let ( property_list, property_sys_list ) = handle_panic ( ctx, || {
491
497
let instance = instance_data_as_script_instance :: < T > ( p_instance) ;
492
498
493
- let property_list: Vec < _ > = borrow_instance ( instance)
494
- . get_property_list ( )
499
+ let property_list = borrow_instance ( instance) . get_property_list ( ) ;
500
+
501
+ let property_sys_list: Box < [ _ ] > = property_list
495
502
. iter ( )
496
503
. map ( |prop| prop. property_sys ( ) )
497
504
. collect ( ) ;
498
505
499
- property_list
506
+ ( property_list, property_sys_list )
500
507
} )
501
508
. unwrap_or_default ( ) ;
502
509
503
510
// SAFETY: list_length has to be a valid pointer to a u32.
504
511
let list_length = unsafe { & mut * r_count } ;
512
+ let return_pointer = transfer_ptr_list_to_godot ( property_sys_list, list_length) ;
513
+
514
+ let instance = instance_data_as_script_instance :: < T > ( p_instance) ;
515
+ instance
516
+ . property_list
517
+ . lock ( )
518
+ . expect ( "Mutex should not be poisoned" )
519
+ . insert ( return_pointer, property_list) ;
505
520
506
- transfer_ptr_list_to_godot ( property_list , list_length )
521
+ return_pointer
507
522
}
508
523
509
524
/// # Safety
@@ -516,23 +531,33 @@ mod script_instance_info {
516
531
) -> * const sys:: GDExtensionMethodInfo {
517
532
let ctx = || format ! ( "error when calling {}::get_method_list" , type_name:: <T >( ) ) ;
518
533
519
- let method_list = handle_panic ( ctx, || {
534
+ let ( method_list, method_sys_list ) = handle_panic ( ctx, || {
520
535
let instance = instance_data_as_script_instance :: < T > ( p_instance) ;
521
536
522
- let method_list: Vec < _ > = borrow_instance ( instance)
523
- . get_method_list ( )
537
+ let method_list = borrow_instance ( instance) . get_method_list ( ) ;
538
+
539
+ let method_sys_list = method_list
524
540
. iter ( )
525
541
. map ( |method| method. method_sys ( ) )
526
542
. collect ( ) ;
527
543
528
- method_list
544
+ ( method_list, method_sys_list )
529
545
} )
530
546
. unwrap_or_default ( ) ;
531
547
532
548
// SAFETY: list_length has to be a valid pointer to a u32.
533
549
let list_length = unsafe { & mut * r_count } ;
550
+ let return_pointer = transfer_ptr_list_to_godot ( method_sys_list, list_length) ;
551
+
552
+ let instance = instance_data_as_script_instance :: < T > ( p_instance) ;
534
553
535
- transfer_ptr_list_to_godot ( method_list, list_length)
554
+ instance
555
+ . method_list
556
+ . lock ( )
557
+ . expect ( "mutex should not be poisoned" )
558
+ . insert ( return_pointer, method_list) ;
559
+
560
+ return_pointer
536
561
}
537
562
538
563
/// # Safety
@@ -561,6 +586,16 @@ mod script_instance_info {
561
586
// and therefore should have the same length as before. get_propery_list_func
562
587
// also guarantees that both vector length and capacity are equal.
563
588
let _drop = transfer_ptr_list_from_godot ( p_prop_info, length) ;
589
+
590
+ // now drop the backing data
591
+ let instance = instance_data_as_script_instance :: < T > ( p_instance) ;
592
+
593
+ let _drop = instance
594
+ . property_list
595
+ . lock ( )
596
+ . expect ( "mutex should not be poisoned" )
597
+ . remove ( & p_prop_info)
598
+ . expect ( "we can not free a list that has not been allocated" ) ;
564
599
}
565
600
566
601
/// # Safety
0 commit comments