55 */
66
77use core:: panic;
8+ use std:: marker:: PhantomData ;
89use std:: { collections:: HashMap , fmt:: Debug , ops:: DerefMut } ;
910
1011use godot:: classes:: Script ;
1112use godot:: meta:: { MethodInfo , PropertyInfo } ;
12- use godot:: obj:: script:: { ScriptInstance , SiMut } ;
13+ use godot:: obj:: script:: { ScriptBaseMut , ScriptInstance , SiMut } ;
14+ use godot:: obj:: GodotClass ;
1315use godot:: prelude:: { GString , Gd , Object , StringName , Variant , VariantType } ;
1416use godot_cell:: blocking:: GdCell ;
1517
1618use super :: { rust_script:: RustScript , rust_script_language:: RustScriptLanguage , SCRIPT_REGISTRY } ;
17- use crate :: script_registry:: GodotScriptObject ;
19+ use crate :: script_registry:: { GodotScriptImpl , GodotScriptObject } ;
1820
1921fn 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+
100149pub ( 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 }
0 commit comments