@@ -9,16 +9,6 @@ use crate::out;
9
9
use godot_ffi as sys;
10
10
11
11
use 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
- }
22
12
23
13
#[ derive( Copy , Clone , Debug ) ]
24
14
pub enum Lifecycle {
@@ -27,76 +17,201 @@ pub enum Lifecycle {
27
17
Dead , // reading this would typically already be too late, only best-effort in case of UB
28
18
}
29
19
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:: * ;
34
22
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:: * ;
41
25
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 ,
50
43
}
51
44
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
+ }
60
115
}
116
+ }
61
117
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 } ;
74
123
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 ,
78
136
}
79
137
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
+ }
89
208
}
209
+ }
90
210
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 ) )
100
215
}
101
216
102
217
pub fn mark_destroyed_by_godot ( & mut self ) {
@@ -127,7 +242,7 @@ impl<T: GodotClass> Drop for InstanceStorage<T> {
127
242
fn drop ( & mut self ) {
128
243
out ! (
129
244
" Storage::drop (rc={}) <{}>" , // -- {:?}",
130
- self . godot_ref_count,
245
+ self . godot_ref_count( ) ,
131
246
type_name:: <T >( ) ,
132
247
//self.user_instance
133
248
) ;
0 commit comments