Skip to content

Commit 92eaeed

Browse files
committed
Unify string parameters across the repo
The types of string parameters across the repo has been regularized according to the following rules that shall be followed from now on: - Methods during the init/registration process should take `&str` for things like identifiers. They may specify explicit lifetimes in their types if necessary, but *not* `'static`. - Manually written methods that abstract over, or mimic API methods should take `impl Into<GodotString>` or `impl Into<NodePath>` depending on the usage, to be consistent with their generated counterparts. Regarding the usage of `&str` in init instead of more specific conversions required by each method: The GDNative API isn't very consistent when it comes to the string types it wants during init. Sometimes, functions may want different types of strings even when they are concepturally similar, like for signal and method registration. This gets more complicated when we add our own library-side logic into the mix, like for the `InitHandle::add_class` family, where allocation is current inevitable even when they are given `&'static str`s. It still makes sense to avoid excessive allocation, but that should not get in the way of future development. `'static` in particular is extremely limiting, and there are very few cases of its usage throughout the library's history that we have not since regretted. It shouldn't be the norm but the rare exception. In any case, class registration is something that only run once in the lifecycle of a game, and for the amount of classes most people are using with `gdnative`, we can afford to be slightly inefficient with strings to make our APIs more consistent, less leaky, and easier to stablize and maintain.
1 parent 7d4ab54 commit 92eaeed

File tree

9 files changed

+34
-38
lines changed

9 files changed

+34
-38
lines changed

Diff for: gdnative-async/src/rt.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::marker::PhantomData;
33

44
use func_state::FuncState;
55
use gdnative_bindings::Object;
6-
use gdnative_core::core_types::{GodotError, Variant};
6+
use gdnative_core::core_types::{GodotError, Variant, GodotString};
77
use gdnative_core::init::InitHandle;
88
use gdnative_core::object::{Instance, SubClass, TInstance, TRef};
99

@@ -77,13 +77,13 @@ impl Context {
7777
pub fn signal<C>(
7878
&self,
7979
obj: TRef<'_, C>,
80-
signal: &str,
80+
signal: impl Into<GodotString>,
8181
) -> Result<future::Yield<Vec<Variant>>, GodotError>
8282
where
8383
C: SubClass<Object>,
8484
{
8585
let (future, resume) = future::make();
86-
bridge::SignalBridge::connect(obj.upcast(), signal, resume)?;
86+
bridge::SignalBridge::connect(obj.upcast(), signal.into(), resume)?;
8787
Ok(future)
8888
}
8989
}
@@ -107,8 +107,8 @@ pub fn register_runtime_with_prefix<S>(handle: &InitHandle, prefix: S)
107107
where
108108
S: Display,
109109
{
110-
handle.add_class_as::<bridge::SignalBridge>(format!("{prefix}SignalBridge"));
111-
handle.add_class_as::<func_state::FuncState>(format!("{prefix}FuncState"));
110+
handle.add_class_as::<bridge::SignalBridge>(&format!("{prefix}SignalBridge"));
111+
handle.add_class_as::<func_state::FuncState>(&format!("{prefix}FuncState"));
112112
}
113113

114114
/// Releases all observers still in use. This should be called in the

Diff for: gdnative-async/src/rt/bridge.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use once_cell::sync::OnceCell;
44
use parking_lot::Mutex;
55

66
use gdnative_bindings::{Object, Reference};
7-
use gdnative_core::core_types::{GodotError, Variant, VariantArray};
7+
use gdnative_core::core_types::{GodotError, Variant, VariantArray, GodotString};
88
use gdnative_core::export::user_data::{ArcData, Map};
99
use gdnative_core::export::{ClassBuilder, Method, NativeClass, NativeClassMethods, Varargs};
1010
use gdnative_core::godot_site;
@@ -58,7 +58,7 @@ impl NativeClass for SignalBridge {
5858
impl SignalBridge {
5959
pub(crate) fn connect(
6060
source: TRef<Object>,
61-
signal: &str,
61+
signal: GodotString,
6262
resume: Resume<Vec<Variant>>,
6363
) -> Result<(), GodotError> {
6464
let mut pool = BRIDGES.get_or_init(Mutex::default).lock();

Diff for: gdnative-bindings/src/utils.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use super::generated::{Engine, Node, SceneTree};
1818
/// invariants must be observed for the resulting node during `'a`, if any.
1919
///
2020
/// [thread-safety]: https://docs.godotengine.org/en/stable/tutorials/threads/thread_safe_apis.html
21-
pub unsafe fn autoload<'a, T>(name: &str) -> Option<TRef<'a, T>>
21+
pub unsafe fn autoload<'a, T>(name: impl Into<NodePath>) -> Option<TRef<'a, T>>
2222
where
2323
T: SubClass<Node>,
2424
{

Diff for: gdnative-core/src/export/class_builder.rs

-6
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,6 @@ use crate::export::*;
1010
use crate::object::NewRef;
1111
use crate::private::get_api;
1212

13-
// TODO(#996): unify string parameters across all buiders
14-
// Potential candidates:
15-
// * &str
16-
// * impl Into<GodotString>
17-
// * impl Into<Cow<'a, str>>
18-
1913
/// Allows registration of exported properties, methods and signals.
2014
///
2115
/// See member functions of this class for usage examples.

Diff for: gdnative-core/src/export/class_registry.rs

+10-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use std::any::TypeId;
2-
use std::borrow::Cow;
32
use std::collections::hash_map::Entry;
43
use std::collections::HashMap;
54
use std::fmt;
@@ -15,7 +14,7 @@ static CLASS_REGISTRY: Lazy<RwLock<HashMap<TypeId, ClassInfo>>> =
1514

1615
#[derive(Clone, Debug)]
1716
pub(crate) struct ClassInfo {
18-
pub name: Cow<'static, str>,
17+
pub name: String,
1918
pub init_level: InitLevel,
2019
}
2120

@@ -31,7 +30,7 @@ where
3130
/// Returns the NativeScript name of the class `C` if it is registered.
3231
/// Can also be used to validate whether or not `C` has been added using `InitHandle::add_class<C>()`
3332
#[inline]
34-
pub(crate) fn class_name<C: NativeClass>() -> Option<Cow<'static, str>> {
33+
pub(crate) fn class_name<C: NativeClass>() -> Option<String> {
3534
with_class_info::<C, _, _>(|i| i.name.clone())
3635
}
3736

@@ -41,8 +40,8 @@ pub(crate) fn class_name<C: NativeClass>() -> Option<Cow<'static, str>> {
4140
/// The returned string should only be used for diagnostic purposes, not for types that the user
4241
/// has to name explicitly. The format is not guaranteed.
4342
#[inline]
44-
pub(crate) fn class_name_or_default<C: NativeClass>() -> Cow<'static, str> {
45-
class_name::<C>().unwrap_or_else(|| Cow::Borrowed(std::any::type_name::<C>()))
43+
pub(crate) fn class_name_or_default<C: NativeClass>() -> String {
44+
class_name::<C>().unwrap_or_else(|| std::any::type_name::<C>().into())
4645
}
4746

4847
/// Registers the class `C` in the class registry, using a custom name at the given level.
@@ -51,14 +50,17 @@ pub(crate) fn class_name_or_default<C: NativeClass>() -> Cow<'static, str> {
5150
/// Returns an error with the old `ClassInfo` if a conflicting entry for `C` was already added.
5251
#[inline]
5352
pub(crate) fn register_class_as<C: NativeClass>(
54-
name: Cow<'static, str>,
53+
name: &str,
5554
init_level: InitLevel,
5655
) -> Result<bool, RegisterError> {
5756
let type_id = TypeId::of::<C>();
5857
let mut registry = CLASS_REGISTRY.write();
5958
match registry.entry(type_id) {
6059
Entry::Vacant(entry) => {
61-
entry.insert(ClassInfo { name, init_level });
60+
entry.insert(ClassInfo {
61+
name: name.into(),
62+
init_level,
63+
});
6264
Ok(true)
6365
}
6466
Entry::Occupied(entry) => {
@@ -86,7 +88,7 @@ pub(crate) fn register_class_as<C: NativeClass>(
8688

8789
#[inline]
8890
#[allow(dead_code)] // Currently unused on platforms with inventory support
89-
pub(crate) fn types_with_init_level(allow: InitLevel, deny: InitLevel) -> Vec<Cow<'static, str>> {
91+
pub(crate) fn types_with_init_level(allow: InitLevel, deny: InitLevel) -> Vec<String> {
9092
let registry = CLASS_REGISTRY.read();
9193
let mut list = registry
9294
.values()

Diff for: gdnative-core/src/export/property/invalid_accessor.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ unsafe impl<'l, C: NativeClass, T> RawSetter<C, T> for InvalidSetter<'l> {
8484
let mut set = sys::godot_property_set_func::default();
8585

8686
let data = Box::new(InvalidAccessorData {
87-
class_name: class_registry::class_name_or_default::<C>().into_owned(),
87+
class_name: class_registry::class_name_or_default::<C>(),
8888
property_name: self.property_name.to_string(),
8989
});
9090

@@ -101,7 +101,7 @@ unsafe impl<'l, C: NativeClass, T> RawGetter<C, T> for InvalidGetter<'l> {
101101
let mut get = sys::godot_property_get_func::default();
102102

103103
let data = Box::new(InvalidAccessorData {
104-
class_name: class_registry::class_name_or_default::<C>().into_owned(),
104+
class_name: class_registry::class_name_or_default::<C>(),
105105
property_name: self.property_name.to_string(),
106106
});
107107

Diff for: gdnative-core/src/init/init_handle.rs

+10-11
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use crate::export::{
44
};
55
use crate::object::{GodotObject, RawObject, TRef};
66
use crate::private::get_api;
7-
use std::borrow::Cow;
87
use std::ffi::CString;
98
use std::ptr;
109

@@ -43,7 +42,7 @@ impl InitHandle {
4342
where
4443
C: NativeClassMethods + StaticallyNamed,
4544
{
46-
self.add_maybe_tool_class_as_with::<C>(Cow::Borrowed(C::CLASS_NAME), false, |builder| {
45+
self.add_maybe_tool_class_as_with::<C>(C::CLASS_NAME, false, |builder| {
4746
C::nativeclass_register_monomorphized(builder);
4847
f(builder);
4948
})
@@ -64,7 +63,7 @@ impl InitHandle {
6463
where
6564
C: NativeClassMethods + StaticallyNamed,
6665
{
67-
self.add_maybe_tool_class_as_with::<C>(Cow::Borrowed(C::CLASS_NAME), true, |builder| {
66+
self.add_maybe_tool_class_as_with::<C>(C::CLASS_NAME, true, |builder| {
6867
C::nativeclass_register_monomorphized(builder);
6968
f(builder);
7069
})
@@ -75,7 +74,7 @@ impl InitHandle {
7574
/// If the type implements [`StaticallyTyped`], that name is ignored in favor of the
7675
/// name provided at registration.
7776
#[inline]
78-
pub fn add_class_as<C>(self, name: String)
77+
pub fn add_class_as<C>(self, name: &str)
7978
where
8079
C: NativeClassMethods,
8180
{
@@ -87,19 +86,19 @@ impl InitHandle {
8786
/// If the type implements [`StaticallyTyped`], that name is ignored in favor of the
8887
/// name provided at registration.
8988
#[inline]
90-
pub fn add_class_as_with<C>(self, name: String, f: impl FnOnce(&ClassBuilder<C>))
89+
pub fn add_class_as_with<C>(self, name: &str, f: impl FnOnce(&ClassBuilder<C>))
9190
where
9291
C: NativeClassMethods,
9392
{
94-
self.add_maybe_tool_class_as_with::<C>(Cow::Owned(name), false, f)
93+
self.add_maybe_tool_class_as_with::<C>(name, false, f)
9594
}
9695

9796
/// Registers a new tool class to the engine
9897
///
9998
/// If the type implements [`StaticallyTyped`], that name is ignored in favor of the
10099
/// name provided at registration.
101100
#[inline]
102-
pub fn add_tool_class_as<C>(self, name: String)
101+
pub fn add_tool_class_as<C>(self, name: &str)
103102
where
104103
C: NativeClassMethods,
105104
{
@@ -111,23 +110,23 @@ impl InitHandle {
111110
/// If the type implements [`StaticallyTyped`], that name is ignored in favor of the
112111
/// name provided at registration.
113112
#[inline]
114-
pub fn add_tool_class_as_with<C>(self, name: String, f: impl FnOnce(&ClassBuilder<C>))
113+
pub fn add_tool_class_as_with<C>(self, name: &str, f: impl FnOnce(&ClassBuilder<C>))
115114
where
116115
C: NativeClassMethods,
117116
{
118-
self.add_maybe_tool_class_as_with::<C>(Cow::Owned(name), true, f)
117+
self.add_maybe_tool_class_as_with::<C>(name, true, f)
119118
}
120119

121120
#[inline]
122121
fn add_maybe_tool_class_as_with<C>(
123122
self,
124-
name: Cow<'static, str>,
123+
name: &str,
125124
is_tool: bool,
126125
f: impl FnOnce(&ClassBuilder<C>),
127126
) where
128127
C: NativeClassMethods,
129128
{
130-
let c_class_name = CString::new(&*name).unwrap();
129+
let c_class_name = CString::new(name).unwrap();
131130

132131
match class_registry::register_class_as::<C>(name, self.init_level) {
133132
Ok(true) => {}

Diff for: gdnative-core/src/object/instance.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::borrow::Cow;
12
use std::fmt::Debug;
23
use std::ptr::NonNull;
34

@@ -599,7 +600,7 @@ where
599600
fn from_variant(variant: &Variant) -> Result<Self, FromVariantError> {
600601
let owner = Ref::<T::Base, Shared>::from_variant(variant)?;
601602
Self::from_base(owner).ok_or(FromVariantError::InvalidInstance {
602-
expected: class_registry::class_name_or_default::<T>(),
603+
expected: Cow::Owned(class_registry::class_name_or_default::<T>()),
603604
})
604605
}
605606
}

Diff for: gdnative/src/globalscope.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
//! [@GDScript]: https://docs.godotengine.org/en/stable/classes/[email protected]
2121
2222
use crate::api::{Resource, ResourceLoader};
23-
use crate::core_types::NodePath;
2423
use crate::object::{memory::RefCounted, GodotObject, Ref, SubClass};
24+
use crate::core_types::GodotString;
2525

2626
#[doc(inline)]
2727
pub use gdnative_core::globalscope::*;
@@ -52,7 +52,7 @@ pub use gdnative_core::globalscope::*;
5252
/// let scene = load::<PackedScene>("res://path/to/Main.tscn").unwrap();
5353
/// ```
5454
#[inline]
55-
pub fn load<T>(path: impl Into<NodePath>) -> Option<Ref<T>>
55+
pub fn load<T>(path: impl Into<GodotString>) -> Option<Ref<T>>
5656
where
5757
T: SubClass<Resource> + GodotObject<Memory = RefCounted>,
5858
{

0 commit comments

Comments
 (0)