@@ -9,16 +9,6 @@ use crate::out;
99use godot_ffi as sys;
1010
1111use std:: any:: type_name;
12- use std:: cell;
13-
14- /// Manages storage and lifecycle of user's extension class instances.
15- pub struct InstanceStorage < T : GodotClass > {
16- user_instance : cell:: RefCell < T > ,
17-
18- // Declared after `user_instance`, is dropped last
19- pub lifecycle : Lifecycle ,
20- godot_ref_count : i32 ,
21- }
2212
2313#[ derive( Copy , Clone , Debug ) ]
2414pub enum Lifecycle {
@@ -27,76 +17,201 @@ pub enum Lifecycle {
2717 Dead , // reading this would typically already be too late, only best-effort in case of UB
2818}
2919
30- /// For all Godot extension classes
31- impl < T : GodotClass > InstanceStorage < T > {
32- pub fn construct ( user_instance : T ) -> Self {
33- out ! ( " Storage::construct <{}>" , type_name:: <T >( ) ) ;
20+ #[ cfg( not( feature = "threads" ) ) ]
21+ pub use single_thread:: * ;
3422
35- Self {
36- user_instance : cell:: RefCell :: new ( user_instance) ,
37- lifecycle : Lifecycle :: Alive ,
38- godot_ref_count : 1 ,
39- }
40- }
23+ #[ cfg( feature = "threads" ) ]
24+ pub use multi_thread:: * ;
4125
42- pub ( crate ) fn on_inc_ref ( & mut self ) {
43- self . godot_ref_count += 1 ;
44- out ! (
45- " Storage::on_inc_ref (rc={}) <{}>" , // -- {:?}",
46- self . godot_ref_count,
47- type_name:: <T >( ) ,
48- //self.user_instance
49- ) ;
26+ #[ cfg( not( feature = "threads" ) ) ]
27+ mod single_thread {
28+ use std:: any:: type_name;
29+ use std:: cell;
30+
31+ use crate :: obj:: GodotClass ;
32+ use crate :: out;
33+
34+ use super :: Lifecycle ;
35+
36+ /// Manages storage and lifecycle of user's extension class instances.
37+ pub struct InstanceStorage < T : GodotClass > {
38+ user_instance : cell:: RefCell < T > ,
39+
40+ // Declared after `user_instance`, is dropped last
41+ pub lifecycle : Lifecycle ,
42+ godot_ref_count : u32 ,
5043 }
5144
52- pub ( crate ) fn on_dec_ref ( & mut self ) {
53- self . godot_ref_count -= 1 ;
54- out ! (
55- " | Storage::on_dec_ref (rc={}) <{}>" , // -- {:?}",
56- self . godot_ref_count,
57- type_name:: <T >( ) ,
58- //self.user_instance
59- ) ;
45+ /// For all Godot extension classes
46+ impl < T : GodotClass > InstanceStorage < T > {
47+ pub fn construct ( user_instance : T ) -> Self {
48+ out ! ( " Storage::construct <{}>" , type_name:: <T >( ) ) ;
49+
50+ Self {
51+ user_instance : cell:: RefCell :: new ( user_instance) ,
52+ lifecycle : Lifecycle :: Alive ,
53+ godot_ref_count : 1 ,
54+ }
55+ }
56+
57+ pub ( crate ) fn on_inc_ref ( & mut self ) {
58+ self . godot_ref_count += 1 ;
59+ out ! (
60+ " Storage::on_inc_ref (rc={}) <{}>" , // -- {:?}",
61+ self . godot_ref_count( ) ,
62+ type_name:: <T >( ) ,
63+ //self.user_instance
64+ ) ;
65+ }
66+
67+ pub ( crate ) fn on_dec_ref ( & mut self ) {
68+ self . godot_ref_count -= 1 ;
69+ out ! (
70+ " | Storage::on_dec_ref (rc={}) <{}>" , // -- {:?}",
71+ self . godot_ref_count( ) ,
72+ type_name:: <T >( ) ,
73+ //self.user_instance
74+ ) ;
75+ }
76+
77+ /* pub fn destroy(&mut self) {
78+ assert!(
79+ self.user_instance.is_some(),
80+ "Cannot destroy user instance which is not yet initialized"
81+ );
82+ assert!(
83+ !self.destroyed,
84+ "Cannot destroy user instance multiple times"
85+ );
86+ self.user_instance = None; // drops T
87+ // TODO drop entire Storage
88+ }*/
89+
90+ pub fn get ( & self ) -> cell:: Ref < T > {
91+ self . user_instance . try_borrow ( ) . unwrap_or_else ( |_e| {
92+ panic ! (
93+ "Gd<T>::bind() failed, already bound; T = {}.\n \
94+ Make sure there is no &mut T live at the time.\n \
95+ This often occurs when calling a GDScript function/signal from Rust, which then calls again Rust code.",
96+ type_name:: <T >( )
97+ )
98+ } )
99+ }
100+
101+ pub fn get_mut ( & mut self ) -> cell:: RefMut < T > {
102+ self . user_instance . try_borrow_mut ( ) . unwrap_or_else ( |_e| {
103+ panic ! (
104+ "Gd<T>::bind_mut() failed, already bound; T = {}.\n \
105+ Make sure there is no &T or &mut T live at the time.\n \
106+ This often occurs when calling a GDScript function/signal from Rust, which then calls again Rust code.",
107+ type_name:: <T >( )
108+ )
109+ } )
110+ }
111+
112+ pub ( super ) fn godot_ref_count ( & self ) -> u32 {
113+ self . godot_ref_count
114+ }
60115 }
116+ }
61117
62- /* pub fn destroy(&mut self) {
63- assert!(
64- self.user_instance.is_some(),
65- "Cannot destroy user instance which is not yet initialized"
66- );
67- assert!(
68- !self.destroyed,
69- "Cannot destroy user instance multiple times"
70- );
71- self.user_instance = None; // drops T
72- // TODO drop entire Storage
73- }*/
118+ #[ cfg( feature = "threads" ) ]
119+ mod multi_thread {
120+ use std:: any:: type_name;
121+ use std:: sync;
122+ use std:: sync:: atomic:: { AtomicU32 , Ordering } ;
74123
75- #[ must_use]
76- pub fn into_raw ( self ) -> * mut Self {
77- Box :: into_raw ( Box :: new ( self ) )
124+ use crate :: obj:: GodotClass ;
125+ use crate :: out;
126+
127+ use super :: Lifecycle ;
128+
129+ /// Manages storage and lifecycle of user's extension class instances.
130+ pub struct InstanceStorage < T : GodotClass > {
131+ user_instance : sync:: RwLock < T > ,
132+
133+ // Declared after `user_instance`, is dropped last
134+ pub lifecycle : Lifecycle ,
135+ godot_ref_count : AtomicU32 ,
78136 }
79137
80- pub fn get ( & self ) -> cell:: Ref < T > {
81- self . user_instance . try_borrow ( ) . unwrap_or_else ( |_e| {
82- panic ! (
83- "Gd<T>::bind() failed, already bound; T = {}.\n \
84- Make sure there is no &mut T live at the time.\n \
85- This often occurs when calling a GDScript function/signal from Rust, which then calls again Rust code.",
86- type_name:: <T >( )
87- )
88- } )
138+ /// For all Godot extension classes
139+ impl < T : GodotClass > InstanceStorage < T > {
140+ pub fn construct ( user_instance : T ) -> Self {
141+ out ! ( " Storage::construct <{}>" , type_name:: <T >( ) ) ;
142+
143+ Self {
144+ user_instance : sync:: RwLock :: new ( user_instance) ,
145+ lifecycle : Lifecycle :: Alive ,
146+ godot_ref_count : AtomicU32 :: new ( 1 ) ,
147+ }
148+ }
149+
150+ pub ( crate ) fn on_inc_ref ( & mut self ) {
151+ self . godot_ref_count . fetch_add ( 1 , Ordering :: Relaxed ) ;
152+ out ! (
153+ " Storage::on_inc_ref (rc={}) <{}>" , // -- {:?}",
154+ self . godot_ref_count( ) ,
155+ type_name:: <T >( ) ,
156+ //self.user_instance
157+ ) ;
158+ }
159+
160+ pub ( crate ) fn on_dec_ref ( & mut self ) {
161+ self . godot_ref_count . fetch_sub ( 1 , Ordering :: Relaxed ) ;
162+ out ! (
163+ " | Storage::on_dec_ref (rc={}) <{}>" , // -- {:?}",
164+ self . godot_ref_count( ) ,
165+ type_name:: <T >( ) ,
166+ //self.user_instance
167+ ) ;
168+ }
169+
170+ /* pub fn destroy(&mut self) {
171+ assert!(
172+ self.user_instance.is_some(),
173+ "Cannot destroy user instance which is not yet initialized"
174+ );
175+ assert!(
176+ !self.destroyed,
177+ "Cannot destroy user instance multiple times"
178+ );
179+ self.user_instance = None; // drops T
180+ // TODO drop entire Storage
181+ }*/
182+
183+ pub fn get ( & self ) -> sync:: RwLockReadGuard < T > {
184+ self . user_instance . read ( ) . unwrap_or_else ( |_e| {
185+ panic ! (
186+ "Gd<T>::bind() failed, already bound; T = {}.\n \
187+ Make sure there is no &mut T live at the time.\n \
188+ This often occurs when calling a GDScript function/signal from Rust, which then calls again Rust code.",
189+ type_name:: <T >( )
190+ )
191+ } )
192+ }
193+
194+ pub fn get_mut ( & mut self ) -> sync:: RwLockWriteGuard < T > {
195+ self . user_instance . write ( ) . unwrap_or_else ( |_e| {
196+ panic ! (
197+ "Gd<T>::bind_mut() failed, already bound; T = {}.\n \
198+ Make sure there is no &T or &mut T live at the time.\n \
199+ This often occurs when calling a GDScript function/signal from Rust, which then calls again Rust code.",
200+ type_name:: <T >( )
201+ )
202+ } )
203+ }
204+
205+ pub ( super ) fn godot_ref_count ( & self ) -> u32 {
206+ self . godot_ref_count . load ( Ordering :: Relaxed )
207+ }
89208 }
209+ }
90210
91- pub fn get_mut ( & mut self ) -> cell:: RefMut < T > {
92- self . user_instance . try_borrow_mut ( ) . unwrap_or_else ( |_e| {
93- panic ! (
94- "Gd<T>::bind_mut() failed, already bound; T = {}.\n \
95- Make sure there is no &T or &mut T live at the time.\n \
96- This often occurs when calling a GDScript function/signal from Rust, which then calls again Rust code.",
97- type_name:: <T >( )
98- )
99- } )
211+ impl < T : GodotClass > InstanceStorage < T > {
212+ #[ must_use]
213+ pub fn into_raw ( self ) -> * mut Self {
214+ Box :: into_raw ( Box :: new ( self ) )
100215 }
101216
102217 pub fn mark_destroyed_by_godot ( & mut self ) {
@@ -127,7 +242,7 @@ impl<T: GodotClass> Drop for InstanceStorage<T> {
127242 fn drop ( & mut self ) {
128243 out ! (
129244 " Storage::drop (rc={}) <{}>" , // -- {:?}",
130- self . godot_ref_count,
245+ self . godot_ref_count( ) ,
131246 type_name:: <T >( ) ,
132247 //self.user_instance
133248 ) ;
0 commit comments