Skip to content

Commit 0e3b149

Browse files
committed
StringName: disable p_is_static, as codegen usages aren't in static variables
1 parent 789e8cb commit 0e3b149

File tree

4 files changed

+21
-10
lines changed

4 files changed

+21
-10
lines changed

godot-codegen/src/util.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub fn c_str(string: &str) -> Literal {
4141
pub fn make_string_name(identifier: &str) -> TokenStream {
4242
let lit = c_str(identifier);
4343

44-
quote! { StringName::__static_cstr(#lit) }
44+
quote! { StringName::__cstr(#lit) }
4545
}
4646

4747
pub fn make_sname_ptr(identifier: &str) -> TokenStream {

godot-core/src/builtin/string/string_name.rs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
use std::fmt;
99

1010
use godot_ffi as sys;
11-
use godot_ffi::interface_fn;
1211
use sys::{ffi_methods, ExtVariantType, GodotFfi};
1312

1413
use crate::builtin::{inner, Encoding, GString, NodePath, Variant};
@@ -84,7 +83,7 @@ impl StringName {
8483
let is_static = sys::conv::SYS_FALSE;
8584
let s = unsafe {
8685
Self::new_with_string_uninit(|string_ptr| {
87-
let ctor = interface_fn!(string_name_new_with_latin1_chars);
86+
let ctor = sys::interface_fn!(string_name_new_with_latin1_chars);
8887
ctor(
8988
string_ptr,
9089
cstr.as_ptr() as *const std::ffi::c_char,
@@ -245,9 +244,20 @@ impl StringName {
245244
inner::InnerStringName::from_outer(self)
246245
}
247246

247+
#[doc(hidden)] // Private for now. Needs API discussion, also regarding overlap with try_from_cstr().
248+
pub fn __cstr(c_str: &'static std::ffi::CStr) -> Self {
249+
// This used to be set to true, but `p_is_static` parameter in Godot should only be enabled if the result is indeed stored
250+
// in a static. See discussion in https://github.com/godot-rust/gdext/pull/1316. We may unify this into a regular constructor,
251+
// or provide a dedicated StringName cache (similar to ClassId cache) in the future, which would be freed on shutdown.
252+
let is_static = false;
253+
254+
Self::__cstr_with_static(c_str, is_static)
255+
}
256+
248257
/// Creates a `StringName` from a static ASCII/Latin-1 `c"string"`.
249258
///
250-
/// This avoids unnecessary copies and allocations and directly uses the backing buffer. Useful for literals.
259+
/// If `is_static` is true, avoids unnecessary copies and allocations and directly uses the backing buffer. However, this must
260+
/// be stored in an actual `static` to not cause leaks/error messages with Godot. For literals, use `is_static=false`.
251261
///
252262
/// Note that while Latin-1 encoding is the most common encoding for c-strings, it isn't a requirement. So if your c-string
253263
/// uses a different encoding (e.g. UTF-8), it is possible that some characters will not show up as expected.
@@ -260,17 +270,17 @@ impl StringName {
260270
/// use godot::builtin::StringName;
261271
///
262272
/// // '±' is a Latin-1 character with codepoint 0xB1. Note that this is not UTF-8, where it would need two bytes.
263-
/// let sname = StringName::__static_cstr(c"\xb1 Latin-1 string");
273+
/// let sname = StringName::__cstr(c"\xb1 Latin-1 string");
264274
/// ```
265275
#[doc(hidden)] // Private for now. Needs API discussion, also regarding overlap with try_from_cstr().
266-
pub fn __static_cstr(c_str: &'static std::ffi::CStr) -> Self {
276+
pub fn __cstr_with_static(c_str: &'static std::ffi::CStr, is_static: bool) -> Self {
267277
// SAFETY: c_str is nul-terminated and remains valid for entire program duration.
268278
unsafe {
269279
Self::new_with_string_uninit(|ptr| {
270280
sys::interface_fn!(string_name_new_with_latin1_chars)(
271281
ptr,
272282
c_str.as_ptr(),
273-
sys::conv::SYS_TRUE, // p_is_static
283+
sys::conv::bool_to_sys(is_static),
274284
)
275285
})
276286
}
@@ -488,6 +498,7 @@ mod serialize {
488498
}
489499

490500
// TODO(v0.4.x): consider re-exposing in public API. Open questions: thread-safety, performance, memory leaks, global overhead.
501+
// Possibly in a more general StringName cache, similar to ClassId. See https://github.com/godot-rust/gdext/pull/1316.
491502
/// Creates and gets a reference to a static `StringName` from a ASCII/Latin-1 `c"string"`.
492503
///
493504
/// This is the fastest way to create a StringName repeatedly, with the result being cached and never released, like `SNAME` in Godot source code. Suitable for scenarios where high performance is required.
@@ -498,6 +509,6 @@ macro_rules! static_sname {
498509

499510
let c_str: &'static std::ffi::CStr = $str;
500511
static SNAME: OnceLock<StringName> = OnceLock::new();
501-
SNAME.get_or_init(|| StringName::__static_cstr(c_str))
512+
SNAME.get_or_init(|| StringName::__cstr_with_static(c_str, true))
502513
}};
503514
}

godot-macros/src/class/data_models/inherent_impl.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ fn add_virtual_script_call(
459459

460460
let code = quote! {
461461
let object_ptr = #object_ptr;
462-
let method_sname = ::godot::builtin::StringName::__static_cstr(#method_name_cstr);
462+
let method_sname = ::godot::builtin::StringName::__cstr(#method_name_cstr);
463463
let method_sname_ptr = method_sname.string_sys();
464464
let has_virtual_override = unsafe { ::godot::private::has_virtual_script_method(object_ptr, method_sname_ptr) };
465465

itest/rust/src/builtin_tests/string/string_name_test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ fn string_name_from_cstr() {
127127
];
128128

129129
for (bytes, string) in cases.into_iter() {
130-
let a = StringName::__static_cstr(bytes);
130+
let a = StringName::__cstr(bytes);
131131
let b = StringName::from(string);
132132

133133
assert_eq!(a, b);

0 commit comments

Comments
 (0)