Skip to content

Commit d093359

Browse files
authored
Merge pull request #714 from joriskleiber/add-gstring-chars
Add `GString::chars` for 4.1
2 parents a9a57a5 + 9bba7b8 commit d093359

File tree

2 files changed

+51
-5
lines changed

2 files changed

+51
-5
lines changed

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

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@ impl GString {
8888
///
8989
/// Note: This operation is *O*(*n*). Consider using [`chars_unchecked`][Self::chars_unchecked]
9090
/// if you can make sure the string is a valid UTF-32.
91+
#[cfg_attr(
92+
since_api = "4.1",
93+
deprecated = "Use `chars()` instead. \n\
94+
Since version 4.1, Godot ensures valid UTF-32, checked and unchecked overloads are no longer needed. \n\
95+
For details, see [godotengine/godot#74760](https://github.com/godotengine/godot/pull/74760)."
96+
)]
9197
pub fn chars_checked(&self) -> &[char] {
9298
unsafe {
9399
let s = self.string_sys();
@@ -111,6 +117,12 @@ impl GString {
111117
/// Make sure the string only contains valid unicode scalar values, currently
112118
/// Godot allows for unpaired surrogates and out of range code points to be appended
113119
/// into the string.
120+
#[cfg_attr(
121+
since_api = "4.1",
122+
deprecated = "Use `chars()` instead. \n\
123+
Since version 4.1, ensures valid UTF-32, checked and unchecked overloads are no longer needed. \n\
124+
For details, see [godotengine/godot#74760](https://github.com/godotengine/godot/pull/74760)."
125+
)]
114126
pub unsafe fn chars_unchecked(&self) -> &[char] {
115127
let s = self.string_sys();
116128
let len = interface_fn!(string_to_utf32_chars)(s, std::ptr::null_mut(), 0);
@@ -123,6 +135,16 @@ impl GString {
123135
std::slice::from_raw_parts(ptr as *const char, len as usize)
124136
}
125137

138+
/// Gets the internal chars slice from a [`GString`].
139+
#[cfg(since_api = "4.1")]
140+
pub fn chars(&self) -> &[char] {
141+
// SAFETY: Godot 4.1 ensures valid UTF-32, making this safe to call.
142+
#[allow(deprecated)]
143+
unsafe {
144+
self.chars_unchecked()
145+
}
146+
}
147+
126148
ffi_methods! {
127149
type sys::GDExtensionStringPtr = *mut Self;
128150

@@ -181,7 +203,17 @@ impl_builtin_traits! {
181203

182204
impl fmt::Display for GString {
183205
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184-
let s: String = self.chars_checked().iter().collect();
206+
let s: String;
207+
208+
#[cfg(before_api = "4.1")]
209+
{
210+
s = self.chars_checked().iter().collect();
211+
}
212+
#[cfg(since_api = "4.1")]
213+
{
214+
s = self.chars().iter().collect();
215+
}
216+
185217
f.write_str(s.as_str())
186218
}
187219
}

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

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,18 +68,32 @@ fn string_clone() {
6868
fn empty_string_chars() {
6969
// Tests regression from #228: Null pointer passed to slice::from_raw_parts
7070
let s = GString::new();
71-
assert_eq!(s.chars_checked(), &[]);
72-
assert_eq!(unsafe { s.chars_unchecked() }, &[]);
71+
72+
#[allow(deprecated)]
73+
{
74+
assert_eq!(s.chars_checked(), &[]);
75+
assert_eq!(unsafe { s.chars_unchecked() }, &[]);
76+
}
77+
#[cfg(since_api = "4.1")]
78+
{
79+
assert_eq!(s.chars(), &[]);
80+
}
7381
}
7482

7583
#[itest]
7684
fn string_chars() {
7785
let string = String::from("some_string");
7886
let string_chars: Vec<char> = string.chars().collect();
7987
let gstring = GString::from(string);
80-
let gstring_chars: Vec<char> = gstring.chars_checked().to_vec();
8188

82-
assert_eq!(gstring_chars, string_chars);
89+
#[allow(deprecated)]
90+
{
91+
assert_eq!(string_chars, gstring.chars_checked().to_vec());
92+
}
93+
#[cfg(since_api = "4.1")]
94+
{
95+
assert_eq!(string_chars, gstring.chars().to_vec());
96+
}
8397
}
8498

8599
#[itest]

0 commit comments

Comments
 (0)