Skip to content

Commit aeed339

Browse files
committed
Added class_registry to internally track which classes have been registered and give better error handling related to issue #602.
Includes the feedback from PR#737 as well as the test failures that were found due to lazy initialization of nativescript Changed error message with the that previously suggested (is the script registered?) now returns a more generic expectation
1 parent 86d7f95 commit aeed339

File tree

6 files changed

+47
-5
lines changed

6 files changed

+47
-5
lines changed

gdnative-core/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ approx = "0.4.0"
2323
glam = "0.14.0"
2424
indexmap = "1.6.0"
2525
ahash = "0.7.0"
26+
once_cell = "1.7.2"
2627

2728
gdnative-impl-proc-macros = { path = "../impl/proc_macros", version = "=0.9.3" }
2829

gdnative-core/src/nativescript/class.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ use crate::private::{get_api, ReferenceCountedClassPlaceholder};
1414
use crate::ref_kind::{ManuallyManaged, RefCounted};
1515
use crate::thread_access::{NonUniqueThreadAccess, Shared, ThreadAccess, ThreadLocal, Unique};
1616

17+
use super::class_registry;
1718
use super::emplace;
18-
1919
/// Trait used for describing and initializing a Godot script class.
2020
///
2121
/// This trait is used to provide data and functionality to the
@@ -321,6 +321,8 @@ impl<T: NativeClass> Instance<T, Unique> {
321321
std::ptr::null_mut(),
322322
);
323323

324+
debug_assert!(class_registry::is_class_registered::<T>(), "`{type_name}` must be registered before it can be used; call `handle.add_class::<{type_name}>()` in your `nativescript_init` callback", type_name = std::any::type_name::<T>());
325+
324326
assert!(
325327
emplace::take::<T>().is_none(),
326328
"emplacement value should be taken by the constructor wrapper (this is a bug in the bindings)",
@@ -330,7 +332,7 @@ impl<T: NativeClass> Instance<T, Unique> {
330332

331333
let owner = variant
332334
.try_to_object::<T::Base>()
333-
.expect("base object should be of the correct type (is the script registered?)")
335+
.expect("the engine should return a base object of the correct type")
334336
.assume_unique();
335337

336338
let script_ptr =
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
use crate::nativescript::NativeClass;
2+
use once_cell::sync::Lazy;
3+
use parking_lot::RwLock;
4+
use std::any::TypeId;
5+
use std::collections::HashSet;
6+
7+
static CLASS_REGISTRY: Lazy<RwLock<HashSet<TypeId>>> = Lazy::new(|| RwLock::new(HashSet::new()));
8+
9+
/// Can be used to validate whether or not `C` has been added using `InitHandle::add_class<C>()`
10+
/// Returns true if added otherwise false.
11+
#[inline]
12+
pub(crate) fn is_class_registered<C: NativeClass>() -> bool {
13+
let type_id = TypeId::of::<C>();
14+
CLASS_REGISTRY.read().contains(&type_id)
15+
}
16+
17+
/// Registers the class `C` in the class registry.
18+
/// Returns `true` if `C` was not already present in the list.
19+
/// Returns `false` if `C` was already added.
20+
#[inline]
21+
pub(crate) fn register_class<C: NativeClass>() -> bool {
22+
let type_id = TypeId::of::<C>();
23+
CLASS_REGISTRY.write().insert(type_id)
24+
}
25+
26+
/// Clears the registry
27+
#[inline]
28+
pub(crate) fn cleanup() {
29+
CLASS_REGISTRY.write().clear();
30+
}

gdnative-core/src/nativescript/init.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ use crate::nativescript::NativeClassMethods;
4646
use crate::nativescript::UserData;
4747
use crate::private::get_api;
4848

49+
use super::class_registry;
4950
use super::emplace;
50-
5151
pub mod method;
5252
pub mod property;
5353

@@ -96,6 +96,12 @@ impl InitHandle {
9696
where
9797
C: NativeClassMethods,
9898
{
99+
if !class_registry::register_class::<C>() {
100+
panic!(
101+
"`{type_name}` has already been registered",
102+
type_name = std::any::type_name::<C>()
103+
);
104+
}
99105
unsafe {
100106
let class_name = CString::new(C::class_name()).unwrap();
101107
let base_name = CString::new(C::Base::class_name()).unwrap();

gdnative-core/src/nativescript/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Types and functions related to the NativeScript extension of GDNative.
22
3+
pub(crate) mod class_registry;
34
mod emplace;
45
mod macros;
56

gdnative-core/src/private.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,10 @@ pub fn get_gdnative_library_sys() -> *mut sys::godot_object {
109109
#[inline]
110110
pub unsafe fn cleanup_internal_state() {
111111
#[cfg(feature = "nativescript")]
112-
crate::nativescript::type_tag::cleanup();
113-
112+
{
113+
crate::nativescript::type_tag::cleanup();
114+
crate::nativescript::class_registry::cleanup();
115+
}
114116
GODOT_API = None;
115117
}
116118

0 commit comments

Comments
 (0)