Skip to content

Commit 04c0b31

Browse files
committed
Remove by-value From conversions between strings
Rationale: there is no "move into" or "reuse buffer" optimization possible when converting between String, GString, StringName and NodePath. However, consuming the source string suggests that there is such a benefit. Implementing From only on references makes this clearer and leaves the original string intact for further use.
1 parent 4737427 commit 04c0b31

File tree

16 files changed

+35
-121
lines changed

16 files changed

+35
-121
lines changed

godot-core/src/builtin/callable.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -713,7 +713,7 @@ mod custom_callable {
713713
r_out: sys::GDExtensionStringPtr,
714714
) {
715715
let c: &T = CallableUserdata::inner_from_raw(callable_userdata);
716-
let s = crate::builtin::GString::from(c.to_string());
716+
let s = GString::from(&c.to_string());
717717

718718
s.move_into_string_ptr(r_out);
719719
*r_is_valid = sys::conv::SYS_TRUE;

godot-core/src/builtin/collections/array.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1334,7 +1334,7 @@ impl<T: ArrayElement> GodotType for Array<T> {
13341334
// Typed arrays use type hint.
13351335
PropertyHintInfo {
13361336
hint: crate::global::PropertyHint::ARRAY_TYPE,
1337-
hint_string: GString::from(element_godot_type_name::<T>()),
1337+
hint_string: GString::from(&element_godot_type_name::<T>()),
13381338
}
13391339
}
13401340
}

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

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -359,12 +359,6 @@ impl From<&[char]> for GString {
359359
}
360360
}
361361

362-
impl From<String> for GString {
363-
fn from(value: String) -> Self {
364-
value.as_str().into()
365-
}
366-
}
367-
368362
impl From<&String> for GString {
369363
fn from(value: &String) -> Self {
370364
value.as_str().into()
@@ -424,15 +418,6 @@ impl From<&StringName> for GString {
424418
}
425419
}
426420

427-
impl From<StringName> for GString {
428-
/// Converts this `StringName` to a `GString`.
429-
///
430-
/// This is identical to `GString::from(&string_name)`, and as such there is no performance benefit.
431-
fn from(string_name: StringName) -> Self {
432-
Self::from(&string_name)
433-
}
434-
}
435-
436421
impl From<&NodePath> for GString {
437422
fn from(path: &NodePath) -> Self {
438423
unsafe {
@@ -445,15 +430,6 @@ impl From<&NodePath> for GString {
445430
}
446431
}
447432

448-
impl From<NodePath> for GString {
449-
/// Converts this `NodePath` to a `GString`.
450-
///
451-
/// This is identical to `GString::from(&path)`, and as such there is no performance benefit.
452-
fn from(path: NodePath) -> Self {
453-
Self::from(&path)
454-
}
455-
}
456-
457433
#[cfg(feature = "serde")]
458434
mod serialize {
459435
use std::fmt::Formatter;

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

Lines changed: 6 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -233,20 +233,16 @@ impl fmt::Debug for NodePath {
233233
impl_rust_string_conv!(NodePath);
234234

235235
impl From<&str> for NodePath {
236+
// NodePath doesn't offer direct construction from bytes; go via GString.
236237
fn from(s: &str) -> Self {
237-
GString::from(s).into()
238-
}
239-
}
240-
241-
impl From<String> for NodePath {
242-
fn from(s: String) -> Self {
243-
GString::from(s).into()
238+
Self::from(&GString::from(s))
244239
}
245240
}
246241

247242
impl From<&String> for NodePath {
248243
fn from(s: &String) -> Self {
249-
GString::from(s).into()
244+
// NodePath doesn't offer direct construction from bytes; go via GString.
245+
Self::from(&GString::from(s))
250246
}
251247
}
252248

@@ -262,27 +258,9 @@ impl From<&GString> for NodePath {
262258
}
263259
}
264260

265-
impl From<GString> for NodePath {
266-
/// Converts this `GString` to a `NodePath`.
267-
///
268-
/// This is identical to `NodePath::from(&string)`, and as such there is no performance benefit.
269-
fn from(string: GString) -> Self {
270-
Self::from(&string)
271-
}
272-
}
273-
274261
impl From<&StringName> for NodePath {
275-
fn from(string_name: &StringName) -> Self {
276-
Self::from(GString::from(string_name))
277-
}
278-
}
279-
280-
impl From<StringName> for NodePath {
281-
/// Converts this `StringName` to a `NodePath`.
282-
///
283-
/// This is identical to `NodePath::from(&string_name)`, and as such there is no performance benefit.
284-
fn from(string_name: StringName) -> Self {
285-
Self::from(GString::from(string_name))
262+
fn from(s: &StringName) -> Self {
263+
Self::from(&GString::from(s))
286264
}
287265
}
288266

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

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ impl StringName {
126126
// This branch is short-circuited if invoked for CStr and Godot 4.2+, which uses `string_name_new_with_latin1_chars`
127127
// (requires nul-termination). In general, fall back to GString conversion.
128128
GString::try_from_bytes_with_nul_check(bytes, Encoding::Latin1, check_nul)
129-
.map(Self::from)
129+
.map(|s| Self::from(&s))
130130
}
131131
Encoding::Utf8 => {
132132
// from_utf8() also checks for intermediate NUL bytes.
@@ -344,12 +344,6 @@ impl From<&str> for StringName {
344344
}
345345
}
346346

347-
impl From<String> for StringName {
348-
fn from(value: String) -> Self {
349-
value.as_str().into()
350-
}
351-
}
352-
353347
impl From<&String> for StringName {
354348
fn from(value: &String) -> Self {
355349
value.as_str().into()
@@ -369,27 +363,9 @@ impl From<&GString> for StringName {
369363
}
370364
}
371365

372-
impl From<GString> for StringName {
373-
/// Converts this `GString` to a `StringName`.
374-
///
375-
/// This is identical to `StringName::from(&string)`, and as such there is no performance benefit.
376-
fn from(string: GString) -> Self {
377-
Self::from(&string)
378-
}
379-
}
380-
381366
impl From<&NodePath> for StringName {
382367
fn from(path: &NodePath) -> Self {
383-
Self::from(GString::from(path))
384-
}
385-
}
386-
387-
impl From<NodePath> for StringName {
388-
/// Converts this `NodePath` to a `StringName`.
389-
///
390-
/// This is identical to `StringName::from(&path)`, and as such there is no performance benefit.
391-
fn from(path: NodePath) -> Self {
392-
Self::from(GString::from(path))
368+
Self::from(&GString::from(path))
393369
}
394370
}
395371

godot-core/src/meta/property_info.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ impl PropertyInfo {
151151
{
152152
self.variant_type == VariantType::ARRAY
153153
&& self.hint_info.hint == PropertyHint::ARRAY_TYPE
154-
&& self.hint_info.hint_string == T::Via::godot_type_name().into()
154+
&& self.hint_info.hint_string == GString::from(&T::Via::godot_type_name())
155155
}
156156

157157
// ------------------------------------------------------------------------------------------------------------------------------------------
@@ -291,7 +291,7 @@ impl PropertyHintInfo {
291291
let hint_string = if sys::GdextBuild::since_api("4.3") {
292292
GString::new()
293293
} else {
294-
GString::from(type_name)
294+
GString::from(&type_name)
295295
};
296296

297297
Self {
@@ -304,23 +304,23 @@ impl PropertyHintInfo {
304304
pub fn var_array_element<T: ArrayElement>() -> Self {
305305
Self {
306306
hint: PropertyHint::ARRAY_TYPE,
307-
hint_string: GString::from(element_godot_type_name::<T>()),
307+
hint_string: GString::from(&element_godot_type_name::<T>()),
308308
}
309309
}
310310

311311
/// Use for `#[export]` properties -- [`PROPERTY_HINT_TYPE_STRING`](PropertyHint::TYPE_STRING) with the **element** type string as hint string.
312312
pub fn export_array_element<T: ArrayElement>() -> Self {
313313
Self {
314314
hint: PropertyHint::TYPE_STRING,
315-
hint_string: GString::from(T::element_type_string()),
315+
hint_string: GString::from(&T::element_type_string()),
316316
}
317317
}
318318

319319
/// Use for `#[export]` properties -- [`PROPERTY_HINT_TYPE_STRING`](PropertyHint::TYPE_STRING) with the **element** type string as hint string.
320320
pub fn export_packed_array_element<T: PackedArrayElement>() -> Self {
321321
Self {
322322
hint: PropertyHint::TYPE_STRING,
323-
hint_string: GString::from(T::element_type_string()),
323+
hint_string: GString::from(&T::element_type_string()),
324324
}
325325
}
326326

@@ -349,7 +349,7 @@ impl PropertyHintInfo {
349349
D: ?Sized + 'static,
350350
{
351351
PropertyHintInfo {
352-
hint_string: GString::from(get_dyn_property_hint_string::<T, D>()),
352+
hint_string: GString::from(&get_dyn_property_hint_string::<T, D>()),
353353
..PropertyHintInfo::export_gd::<T>()
354354
}
355355
}

godot-core/src/registry/property/mod.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ pub mod export_info_functions {
315315

316316
PropertyHintInfo {
317317
hint: PropertyHint::RANGE,
318-
hint_string: hint_string.into(),
318+
hint_string: GString::from(&hint_string),
319319
}
320320
}
321321

@@ -381,7 +381,7 @@ pub mod export_info_functions {
381381

382382
PropertyHintInfo {
383383
hint: PropertyHint::ENUM,
384-
hint_string: hint_string.into(),
384+
hint_string: GString::from(&hint_string),
385385
}
386386
}
387387

@@ -390,7 +390,7 @@ pub mod export_info_functions {
390390

391391
PropertyHintInfo {
392392
hint: PropertyHint::EXP_EASING,
393-
hint_string: hint_string.into(),
393+
hint_string: GString::from(&hint_string),
394394
}
395395
}
396396

@@ -414,7 +414,7 @@ pub mod export_info_functions {
414414

415415
PropertyHintInfo {
416416
hint: PropertyHint::FLAGS,
417-
hint_string: hint_string.into(),
417+
hint_string: GString::from(&hint_string),
418418
}
419419
}
420420

@@ -493,7 +493,7 @@ pub mod export_info_functions {
493493

494494
PropertyHintInfo {
495495
hint: PropertyHint::TYPE_STRING,
496-
hint_string: format!("{hint_string}:{filter}").into(),
496+
hint_string: GString::from(&format!("{hint_string}:{filter}")),
497497
}
498498
}
499499

godot-core/src/storage/instance_storage.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ pub unsafe fn destroy_storage<T: GodotClass>(instance_ptr: sys::GDExtensionClass
217217
// In Debug mode, crash which may trigger breakpoint.
218218
// In Release mode, leak player object (Godot philosophy: don't crash if somehow avoidable). Likely leads to follow-up issues.
219219
if cfg!(debug_assertions) {
220-
let error = crate::builtin::GString::from(error);
220+
let error = crate::builtin::GString::from(&error);
221221
crate::classes::Os::singleton().crash(&error);
222222
} else {
223223
leak_rust_object = true;

godot-macros/src/derive/data_models/c_style_enum.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ impl CStyleEnum {
115115
}
116116

117117
quote! {
118-
format!(#fmt, #(#fmt_args),*)
118+
// & because it is passed to GString::from().
119+
&format!(#fmt, #(#fmt_args),*)
119120
}
120121
}
121122

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

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,6 @@ fn string_conversion() {
2828
let back = String::from(&second);
2929

3030
assert_eq!(string, back);
31-
32-
let second = GString::from(string.clone());
33-
let back = String::from(second);
34-
35-
assert_eq!(string, back);
3631
}
3732

3833
#[itest]
@@ -75,7 +70,7 @@ fn string_chars() {
7570

7671
let string = String::from("ö🍎A💡");
7772
let string_chars: Vec<char> = string.chars().collect();
78-
let gstring = GString::from(string);
73+
let gstring = GString::from(&string);
7974

8075
assert_eq!(gstring.chars(), string_chars.as_slice());
8176
assert_eq!(

0 commit comments

Comments
 (0)