Skip to content

Commit 6b38c9e

Browse files
authored
Script call context is incomplete (#44)
1 parent a508c30 commit 6b38c9e

File tree

6 files changed

+103
-39
lines changed

6 files changed

+103
-39
lines changed

derive/src/impl_attribute.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,10 @@ pub fn godot_script_impl(
151151
let trait_impl = quote_spanned! {
152152
current_type.span() =>
153153
impl ::godot_rust_script::GodotScriptImpl for #current_type {
154+
type ImplBase = <Self as GodotScript>::Base;
155+
154156
#[allow(unused_variables)]
155-
fn call_fn(&mut self, name: #string_name_ty, args: &[&#variant_ty], ctx: ::godot_rust_script::Context) -> ::std::result::Result<#variant_ty, #call_error_ty> {
157+
fn call_fn(&mut self, name: #string_name_ty, args: &[&#variant_ty], ctx: ::godot_rust_script::Context<Self>) -> ::std::result::Result<#variant_ty, #call_error_ty> {
156158
match name.to_string().as_str() {
157159
#method_dispatch
158160

derive/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,13 @@ pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
128128

129129
let output = quote! {
130130
impl ::godot_rust_script::GodotScript for #script_type_ident {
131+
type Base = #base_class;
132+
131133
#get_fields_impl
132134

133135
#set_fields_impl
134136

135-
fn call(&mut self, name: #string_name_ty, args: &[&#variant_ty], ctx: ::godot_rust_script::Context) -> ::std::result::Result<#variant_ty, #call_error_ty> {
137+
fn call(&mut self, name: #string_name_ty, args: &[&#variant_ty], ctx: ::godot_rust_script::Context<Self>) -> ::std::result::Result<#variant_ty, #call_error_ty> {
136138
::godot_rust_script::GodotScriptImpl::call_fn(self, name, args, ctx)
137139
}
138140

rust-script/src/runtime/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use crate::{
2929

3030
use self::rust_script_language::RustScriptLanguage;
3131

32-
pub use rust_script_instance::Context;
32+
pub use rust_script_instance::{Context, GenericContext};
3333

3434
#[macro_export]
3535
macro_rules! setup {

rust-script/src/runtime/rust_script_instance.rs

Lines changed: 77 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,18 @@
55
*/
66

77
use core::panic;
8+
use std::marker::PhantomData;
89
use std::{collections::HashMap, fmt::Debug, ops::DerefMut};
910

1011
use godot::classes::Script;
1112
use godot::meta::{MethodInfo, PropertyInfo};
12-
use godot::obj::script::{ScriptInstance, SiMut};
13+
use godot::obj::script::{ScriptBaseMut, ScriptInstance, SiMut};
14+
use godot::obj::GodotClass;
1315
use godot::prelude::{GString, Gd, Object, StringName, Variant, VariantType};
1416
use godot_cell::blocking::GdCell;
1517

1618
use super::{rust_script::RustScript, rust_script_language::RustScriptLanguage, SCRIPT_REGISTRY};
17-
use crate::script_registry::GodotScriptObject;
19+
use crate::script_registry::{GodotScriptImpl, GodotScriptObject};
1820

1921
fn script_method_list(script: &Gd<RustScript>) -> Box<[MethodInfo]> {
2022
let rs = script.bind();
@@ -48,30 +50,45 @@ fn script_property_list(script: &Gd<RustScript>) -> Box<[PropertyInfo]> {
4850
props
4951
}
5052

51-
pub struct Context<'a> {
52-
cell: &'a GdCell<Box<dyn GodotScriptObject>>,
53+
pub struct GenericContext<'a> {
54+
cell: *const GdCell<Box<dyn GodotScriptObject>>,
5355
data_ptr: *mut Box<dyn GodotScriptObject>,
56+
base: ScriptBaseMut<'a, RustScriptInstance>,
5457
}
5558

56-
impl<'a> Debug for Context<'a> {
57-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58-
f.write_str("Context { <Call Context> }")
59-
}
60-
}
61-
62-
impl<'a> Context<'a> {
59+
impl<'a> GenericContext<'a> {
6360
unsafe fn new(
64-
cell: &'a GdCell<Box<dyn GodotScriptObject>>,
61+
cell: *const GdCell<Box<dyn GodotScriptObject>>,
6562
data_ptr: *mut Box<dyn GodotScriptObject>,
63+
base: ScriptBaseMut<'a, RustScriptInstance>,
6664
) -> Self {
67-
Self { cell, data_ptr }
65+
Self {
66+
cell,
67+
data_ptr,
68+
base,
69+
}
70+
}
71+
}
72+
73+
pub struct Context<'a, Script: GodotScriptImpl + ?Sized> {
74+
cell: *const GdCell<Box<dyn GodotScriptObject>>,
75+
data_ptr: *mut Box<dyn GodotScriptObject>,
76+
base: ScriptBaseMut<'a, RustScriptInstance>,
77+
base_type: PhantomData<Script>,
78+
}
79+
80+
impl<'a, Script: GodotScriptImpl> Debug for Context<'a, Script> {
81+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82+
f.write_str("Context { <Call Context> }")
6883
}
84+
}
6985

70-
pub fn reentrant_scope<T: GodotScriptObject + 'static, R>(
86+
impl<'a, Script: GodotScriptImpl> Context<'a, Script> {
87+
pub fn reentrant_scope<T: GodotScriptObject + 'static, Args, Return>(
7188
&mut self,
7289
self_ref: &mut T,
73-
cb: impl FnOnce() -> R,
74-
) -> R {
90+
scope: impl ReentrantScope<Script::ImplBase, Args, Return>,
91+
) -> Return {
7592
let known_ptr = unsafe {
7693
let any = (*self.data_ptr).as_any_mut();
7794

@@ -84,19 +101,51 @@ impl<'a> Context<'a> {
84101
panic!("unable to create reentrant scope with unrelated self reference!");
85102
}
86103

87-
let guard = self
88-
.cell
89-
.make_inaccessible(unsafe { &mut *self.data_ptr })
90-
.unwrap();
104+
let current_ref = unsafe { &mut *self.data_ptr };
105+
let cell = unsafe { &*self.cell };
106+
let guard = cell.make_inaccessible(current_ref).unwrap();
91107

92-
let result = cb();
108+
let result = scope.run(self.base.deref_mut().clone().cast::<Script::ImplBase>());
93109

94110
drop(guard);
95111

96112
result
97113
}
98114
}
99115

116+
impl<'a, Script: GodotScriptImpl> From<GenericContext<'a>> for Context<'a, Script> {
117+
fn from(value: GenericContext<'a>) -> Self {
118+
let GenericContext {
119+
cell,
120+
data_ptr,
121+
base,
122+
} = value;
123+
124+
Self {
125+
cell,
126+
data_ptr,
127+
base,
128+
base_type: PhantomData,
129+
}
130+
}
131+
}
132+
133+
pub trait ReentrantScope<Base: GodotClass, Args, Return> {
134+
fn run(self, base: Gd<Base>) -> Return;
135+
}
136+
137+
impl<Base: GodotClass, F: FnOnce() -> R, R> ReentrantScope<Base, (), R> for F {
138+
fn run(self, _base: Gd<Base>) -> R {
139+
self()
140+
}
141+
}
142+
143+
impl<Base: GodotClass, F: FnOnce(Gd<Base>) -> R, R> ReentrantScope<Base, Gd<Base>, R> for F {
144+
fn run(self, base: Gd<Base>) -> R {
145+
self(base)
146+
}
147+
}
148+
100149
pub(super) struct RustScriptInstance {
101150
data: GdCell<Box<dyn GodotScriptObject>>,
102151

@@ -151,16 +200,19 @@ impl ScriptInstance for RustScriptInstance {
151200
}
152201

153202
fn call(
154-
this: SiMut<Self>,
203+
mut this: SiMut<Self>,
155204
method: StringName,
156205
args: &[&Variant],
157206
) -> Result<Variant, godot::sys::GDExtensionCallErrorType> {
158-
let cell = &this.data;
159-
let mut data_guard = cell.borrow_mut().unwrap();
207+
let cell: *const _ = &this.data;
208+
209+
let base = this.base_mut();
210+
211+
let mut data_guard = unsafe { &*cell }.borrow_mut().unwrap();
160212
let data = data_guard.deref_mut();
161213
let data_ptr = data as *mut _;
162214

163-
let context = unsafe { Context::new(cell, data_ptr) };
215+
let context = unsafe { GenericContext::new(cell, data_ptr, base) };
164216

165217
data.call(method, args, context)
166218
}

rust-script/src/script_registry.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,22 @@ use std::{any::Any, collections::HashMap, fmt::Debug, sync::Arc};
88

99
use godot::global::{MethodFlags, PropertyHint, PropertyUsageFlags};
1010
use godot::meta::{ClassName, MethodInfo, PropertyInfo};
11-
use godot::obj::{EngineBitfield, EngineEnum};
11+
use godot::obj::{EngineBitfield, EngineEnum, Inherits};
1212
use godot::prelude::{GString, Gd, Object, StringName, Variant};
1313
use godot::sys::VariantType;
1414

15-
use crate::Context;
15+
use crate::runtime::{Context, GenericContext};
16+
17+
pub trait GodotScript: Debug + GodotScriptImpl<ImplBase = Self::Base> {
18+
type Base: Inherits<Object>;
1619

17-
pub trait GodotScript: Debug + GodotScriptImpl {
1820
fn set(&mut self, name: StringName, value: Variant) -> bool;
1921
fn get(&self, name: StringName) -> Option<Variant>;
2022
fn call(
2123
&mut self,
2224
method: StringName,
2325
args: &[&Variant],
24-
context: Context,
26+
context: Context<'_, Self>,
2527
) -> Result<Variant, godot::sys::GDExtensionCallErrorType>;
2628

2729
fn to_string(&self) -> String;
@@ -31,11 +33,13 @@ pub trait GodotScript: Debug + GodotScriptImpl {
3133
}
3234

3335
pub trait GodotScriptImpl {
36+
type ImplBase: Inherits<Object>;
37+
3438
fn call_fn(
3539
&mut self,
3640
name: StringName,
3741
args: &[&Variant],
38-
context: Context,
42+
context: Context<Self>,
3943
) -> Result<Variant, godot::sys::GDExtensionCallErrorType>;
4044
}
4145

@@ -46,7 +50,7 @@ pub trait GodotScriptObject {
4650
&mut self,
4751
method: StringName,
4852
args: &[&Variant],
49-
context: Context,
53+
context: GenericContext,
5054
) -> Result<Variant, godot::sys::GDExtensionCallErrorType>;
5155
fn to_string(&self) -> String;
5256
fn property_state(&self) -> HashMap<StringName, Variant>;
@@ -67,9 +71,9 @@ impl<T: GodotScript + 'static> GodotScriptObject for T {
6771
&mut self,
6872
method: StringName,
6973
args: &[&Variant],
70-
context: Context,
74+
context: GenericContext,
7175
) -> Result<Variant, godot::sys::GDExtensionCallErrorType> {
72-
GodotScript::call(self, method, args, context)
76+
GodotScript::call(self, method, args, Context::from(context))
7377
}
7478

7579
fn to_string(&self) -> String {

rust-script/tests/script_derive.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
use godot::builtin::{GString, StringName};
88
use godot::classes::Node;
9-
use godot::obj::Gd;
9+
use godot::obj::{Gd, NewAlloc};
1010
use godot_rust_script::{godot_script_impl, Context, GodotScript};
1111

1212
#[derive(GodotScript, Debug)]
@@ -19,7 +19,7 @@ struct TestScript {
1919
#[export(enum_options = ["inactive", "water", "teargas"])]
2020
pub enum_prop: u8,
2121

22-
base: Gd<Node>,
22+
base: Gd<<Self as GodotScript>::Base>,
2323
}
2424

2525
#[godot_script_impl]
@@ -28,14 +28,18 @@ impl TestScript {
2828
value > 2
2929
}
3030

31-
pub fn action(&mut self, input: GString, mut ctx: Context) -> bool {
31+
pub fn action(&mut self, input: GString, mut ctx: Context<Self>) -> bool {
3232
let result = input.len() > 2;
3333
let mut base = self.base.clone();
3434

3535
ctx.reentrant_scope(self, || {
3636
base.emit_signal(StringName::from("hit"), &[]);
3737
});
3838

39+
ctx.reentrant_scope(self, |mut base: Gd<Node>| {
40+
base.set_owner(Node::new_alloc());
41+
});
42+
3943
result
4044
}
4145
}

0 commit comments

Comments
 (0)