Skip to content

Commit 18dd197

Browse files
committed
Store Property / Method list in ScriptInstanceData #647
1 parent fe5b02b commit 18dd197

File tree

3 files changed

+60
-23
lines changed

3 files changed

+60
-23
lines changed

godot-core/src/builtin/meta/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ where
246246
/// Rusty abstraction of `sys::GDExtensionPropertyInfo`.
247247
///
248248
/// Keeps the actual allocated values (the `sys` equivalent only keeps pointers, which fall out of scope).
249-
#[derive(Debug)]
249+
#[derive(Debug, Clone)]
250250
// Note: is not #[non_exhaustive], so adding fields is a breaking change. Mostly used internally at the moment though.
251251
pub struct PropertyInfo {
252252
pub variant_type: VariantType,
@@ -288,7 +288,7 @@ impl PropertyInfo {
288288
}
289289
}
290290

291-
#[derive(Debug)]
291+
#[derive(Debug, Clone)]
292292
pub struct MethodInfo {
293293
pub id: i32,
294294
pub method_name: StringName,

godot-core/src/engine/script_instance.rs

Lines changed: 52 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
*/
77

88
use std::cell::RefCell;
9+
use std::collections::HashMap;
910
use std::ffi::c_void;
11+
use std::sync::Mutex;
1012

1113
use crate::builtin::meta::{MethodInfo, PropertyInfo};
1214
use crate::builtin::{GString, StringName, Variant, VariantType};
@@ -78,10 +80,10 @@ pub trait ScriptInstance {
7880
fn get_property(&self, name: StringName) -> Option<Variant>;
7981

8082
/// 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>;
8284

8385
/// 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>;
8587

8688
/// Method invoker for Godot's virtual dispatch system. The engine will call this function when it wants to call a method on the script.
8789
///
@@ -150,11 +152,11 @@ impl<T: ScriptInstance + ?Sized> ScriptInstance for Box<T> {
150152
self.as_ref().get_property(name)
151153
}
152154

153-
fn get_property_list(&self) -> &[PropertyInfo] {
155+
fn get_property_list(&self) -> Vec<PropertyInfo> {
154156
self.as_ref().get_property_list()
155157
}
156158

157-
fn get_method_list(&self) -> &[MethodInfo] {
159+
fn get_method_list(&self) -> Vec<MethodInfo> {
158160
self.as_ref().get_method_list()
159161
}
160162

@@ -219,6 +221,8 @@ type ScriptInstanceInfo = sys::GDExtensionScriptInstanceInfo2;
219221
struct ScriptInstanceData<T: ScriptInstance> {
220222
inner: RefCell<T>,
221223
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>>>,
222226
}
223227

224228
impl<T: ScriptInstance> Drop for ScriptInstanceData<T> {
@@ -290,6 +294,8 @@ pub fn create_script_instance<T: ScriptInstance>(rs_instance: T) -> *mut c_void
290294
let data = ScriptInstanceData {
291295
inner: RefCell::new(rs_instance),
292296
script_instance_ptr: instance_ptr,
297+
property_list: Default::default(),
298+
method_list: Default::default(),
293299
};
294300

295301
let data_ptr = Box::into_raw(Box::new(data));
@@ -382,13 +388,13 @@ mod script_instance_info {
382388
/// # Safety
383389
///
384390
/// - 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 {
386392
*list_length = ptr_list.len() as u32;
387393

388-
let ptr = Box::into_raw(ptr_list.into_boxed_slice());
394+
let ptr = Box::into_raw(ptr_list);
389395

390396
// 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() }
392398
}
393399

394400
/// The returned pointer's lifetime is equal to the lifetime of `script`
@@ -505,23 +511,32 @@ mod script_instance_info {
505511
) -> *const sys::GDExtensionPropertyInfo {
506512
let ctx = || format!("error when calling {}::get_property_list", type_name::<T>());
507513

508-
let property_list = handle_panic(ctx, || {
514+
let (property_list, property_sys_list) = handle_panic(ctx, || {
509515
let instance = instance_data_as_script_instance::<T>(p_instance);
510516

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
513520
.iter()
514521
.map(|prop| prop.property_sys())
515522
.collect();
516523

517-
property_list
524+
(property_list, property_sys_list)
518525
})
519526
.unwrap_or_default();
520527

521528
// SAFETY: list_length has to be a valid pointer to a u32.
522529
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);
523538

524-
transfer_ptr_list_to_godot(property_list, list_length)
539+
return_pointer
525540
}
526541

527542
/// # Safety
@@ -534,23 +549,33 @@ mod script_instance_info {
534549
) -> *const sys::GDExtensionMethodInfo {
535550
let ctx = || format!("error when calling {}::get_method_list", type_name::<T>());
536551

537-
let method_list = handle_panic(ctx, || {
552+
let (method_list, method_sys_list) = handle_panic(ctx, || {
538553
let instance = instance_data_as_script_instance::<T>(p_instance);
539554

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
542558
.iter()
543559
.map(|method| method.method_sys())
544560
.collect();
545561

546-
method_list
562+
(method_list, method_sys_list)
547563
})
548564
.unwrap_or_default();
549565

550566
// SAFETY: list_length has to be a valid pointer to a u32.
551567
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);
552571

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
554579
}
555580

556581
/// # Safety
@@ -579,6 +604,16 @@ mod script_instance_info {
579604
// and therefore should have the same length as before. get_propery_list_func
580605
// also guarantees that both vector length and capacity are equal.
581606
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");
582617
}
583618

584619
/// # Safety

itest/rust/src/builtin_tests/script/script_instance_tests.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ impl IScriptExtension for TestScript {
3838
struct TestScriptInstance {
3939
/// A field to store the value of the `script_property_b` during tests.
4040
script_property_b: bool,
41+
#[allow(clippy::arc_with_non_send_sync)]
4142
prop_list: Vec<PropertyInfo>,
43+
#[allow(clippy::arc_with_non_send_sync)]
4244
method_list: Vec<MethodInfo>,
4345
script: Gd<Script>,
4446
}
@@ -116,12 +118,12 @@ impl ScriptInstance for TestScriptInstance {
116118
}
117119
}
118120

119-
fn get_property_list(&self) -> &[PropertyInfo] {
120-
&self.prop_list
121+
fn get_property_list(&self) -> Vec<PropertyInfo> {
122+
self.prop_list.clone()
121123
}
122124

123-
fn get_method_list(&self) -> &[MethodInfo] {
124-
&self.method_list
125+
fn get_method_list(&self) -> Vec<MethodInfo> {
126+
self.method_list.clone()
125127
}
126128

127129
fn call(

0 commit comments

Comments
 (0)