Skip to content

Commit c10b7a7

Browse files
committed
wip2
1 parent f7dd12b commit c10b7a7

File tree

5 files changed

+59
-25
lines changed

5 files changed

+59
-25
lines changed

godot-core/src/obj/base.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,5 @@ impl<T: GodotClass> DerefMut for Base<T> {
8484
&mut self.obj
8585
}
8686
}
87+
88+

godot-core/src/storage.rs

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,17 @@ use std::any::type_name;
1212

1313
#[derive(Copy, Clone, Debug)]
1414
pub enum Lifecycle {
15+
// Warning: when reordering/changing enumerators, update match in AtomicLifecycle below
1516
Alive,
1617
Destroying,
1718
Dead, // reading this would typically already be too late, only best-effort in case of UB
1819
}
1920

2021
#[cfg(not(feature = "threads"))]
21-
pub use single_thread::*;
22+
pub(crate) use single_thread::*;
2223

2324
#[cfg(feature = "threads")]
24-
pub use multi_thread::*;
25+
pub(crate) use multi_thread::*;
2526

2627
#[cfg(not(feature = "threads"))]
2728
mod single_thread {
@@ -115,21 +116,46 @@ mod single_thread {
115116
#[cfg(feature = "threads")]
116117
mod multi_thread {
117118
use std::any::type_name;
119+
use std::sync;
118120
use std::sync::atomic::{AtomicU32, Ordering};
119-
use std::{cell, sync};
120121

121122
use crate::obj::{Base, GodotClass};
122-
use crate::{out, sys};
123+
use crate::out;
123124

124125
use super::Lifecycle;
125126

127+
pub struct AtomicLifecycle {
128+
atomic: AtomicU32,
129+
}
130+
131+
impl AtomicLifecycle {
132+
pub fn new(value: Lifecycle) -> Self {
133+
Self {
134+
atomic: AtomicU32::new(value as u32),
135+
}
136+
}
137+
138+
pub fn get(&self) -> Lifecycle {
139+
match self.atomic.load(Ordering::Relaxed) {
140+
0 => Lifecycle::Alive,
141+
1 => Lifecycle::Dead,
142+
2 => Lifecycle::Destroying,
143+
other => panic!("Invalid lifecycle {other}"),
144+
}
145+
}
146+
147+
pub fn set(&self, value: Lifecycle) {
148+
self.atomic.store(value as u32, Ordering::Relaxed);
149+
}
150+
}
151+
126152
/// Manages storage and lifecycle of user's extension class instances.
127153
pub struct InstanceStorage<T: GodotClass> {
128154
user_instance: sync::RwLock<T>,
129155
cached_base: Base<T::Base>,
130156

131157
// Declared after `user_instance`, is dropped last
132-
pub lifecycle: cell::Cell<Lifecycle>,
158+
pub lifecycle: AtomicLifecycle,
133159
godot_ref_count: AtomicU32,
134160
}
135161

@@ -141,12 +167,12 @@ mod multi_thread {
141167
Self {
142168
user_instance: sync::RwLock::new(user_instance),
143169
cached_base,
144-
lifecycle: cell::Cell::new(Lifecycle::Alive),
170+
lifecycle: AtomicLifecycle::new(Lifecycle::Alive),
145171
godot_ref_count: AtomicU32::new(1),
146172
}
147173
}
148174

149-
pub(crate) fn on_inc_ref(&mut self) {
175+
pub(crate) fn on_inc_ref(&self) {
150176
self.godot_ref_count.fetch_add(1, Ordering::Relaxed);
151177
out!(
152178
" Storage::on_inc_ref (rc={}) <{}>", // -- {:?}",
@@ -156,7 +182,7 @@ mod multi_thread {
156182
);
157183
}
158184

159-
pub(crate) fn on_dec_ref(&mut self) {
185+
pub(crate) fn on_dec_ref(&self) {
160186
self.godot_ref_count.fetch_sub(1, Ordering::Relaxed);
161187
out!(
162188
" | Storage::on_dec_ref (rc={}) <{}>", // -- {:?}",
@@ -195,7 +221,15 @@ mod multi_thread {
195221
pub(super) fn godot_ref_count(&self) -> u32 {
196222
self.godot_ref_count.load(Ordering::Relaxed)
197223
}
224+
225+
// TODO enable once there is better thread support
226+
//fn __static_type_check() {
227+
// enforce_sync::<InstanceStorage<T>>();
228+
//}
198229
}
230+
231+
// Make sure storage is Sync in multi-threaded case, as it can be concurrently accessed through aliased Gd<T> pointers.
232+
//fn enforce_sync<T: Sync>() {}
199233
}
200234

201235
impl<T: GodotClass> InstanceStorage<T> {
@@ -267,6 +301,9 @@ pub unsafe fn destroy_storage<T: GodotClass>(instance_ptr: sys::GDExtensionClass
267301
let _drop = Box::from_raw(instance_ptr as *mut InstanceStorage<T>);
268302
}
269303

304+
// ----------------------------------------------------------------------------------------------------------------------------------------------
305+
// Callbacks
306+
270307
pub fn nop_instance_callbacks() -> sys::GDExtensionInstanceBindingCallbacks {
271308
// These could also be null pointers, if they are definitely not invoked (e.g. create_callback only passed to object_get_instance_binding(),
272309
// when there is already a binding). Current "empty but not null" impl corresponds to godot-cpp (wrapped.hpp).

itest/rust/src/object_test.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -763,9 +763,6 @@ pub mod object_test_gd {
763763
#[derive(GodotClass)]
764764
#[class(base=Object)]
765765
pub struct CustomConstructor {
766-
#[base]
767-
base: Base<Object>,
768-
769766
#[var]
770767
pub val: i64,
771768
}
@@ -774,7 +771,7 @@ pub mod object_test_gd {
774771
impl CustomConstructor {
775772
#[func]
776773
pub fn construct_object(val: i64) -> Gd<CustomConstructor> {
777-
Gd::with_base(|base| Self { base, val })
774+
Gd::with_base(|_base| Self { val })
778775
}
779776
}
780777
}
@@ -804,10 +801,7 @@ impl DoubleUse {
804801

805802
#[derive(GodotClass)]
806803
#[class(init, base=Object)]
807-
struct SignalEmitter {
808-
#[base]
809-
base: Base<Object>,
810-
}
804+
struct SignalEmitter {}
811805

812806
#[godot_api]
813807
impl SignalEmitter {

itest/rust/src/property_test.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,28 +15,33 @@ use godot::{
1515
#[derive(GodotClass)]
1616
#[class(base=Node)]
1717
struct HasProperty {
18-
#[base]
19-
base: Base<Node>,
20-
2118
#[var]
2219
int_val: i32,
20+
2321
#[var(get = get_int_val_read)]
2422
int_val_read: i32,
23+
2524
#[var(set = set_int_val_write)]
2625
int_val_write: i32,
26+
2727
#[var(get = get_int_val_rw, set = set_int_val_rw)]
2828
int_val_rw: i32,
29+
2930
#[var(get = get_int_val_getter, set)]
3031
int_val_getter: i32,
32+
3133
#[var(get, set = set_int_val_setter)]
3234
int_val_setter: i32,
3335

3436
#[var(get = get_string_val, set = set_string_val)]
3537
string_val: GodotString,
38+
3639
#[var(get = get_object_val, set = set_object_val)]
3740
object_val: Option<Gd<Object>>,
41+
3842
#[var]
3943
texture_val: Gd<Texture>,
44+
4045
#[var(get = get_texture_val, set = set_texture_val, hint = PROPERTY_HINT_RESOURCE_TYPE, hint_string = "Texture")]
4146
texture_val_rw: Option<Gd<Texture>>,
4247
}
@@ -120,7 +125,7 @@ impl HasProperty {
120125

121126
#[godot_api]
122127
impl NodeVirtual for HasProperty {
123-
fn init(base: Base<Node>) -> Self {
128+
fn init(_base: Base<Node>) -> Self {
124129
HasProperty {
125130
int_val: 0,
126131
int_val_read: 2,
@@ -132,7 +137,6 @@ impl NodeVirtual for HasProperty {
132137
string_val: GodotString::new(),
133138
texture_val: Texture::new(),
134139
texture_val_rw: None,
135-
base,
136140
}
137141
}
138142
}

itest/rust/src/signal_test.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,7 @@ use crate::itest;
1717

1818
#[derive(GodotClass)]
1919
#[class(init, base=Object)]
20-
struct Emitter {
21-
#[base]
22-
base: Base<Object>,
23-
}
20+
struct Emitter {}
2421

2522
#[godot_api]
2623
impl Emitter {

0 commit comments

Comments
 (0)