Skip to content

Commit 5d7a7fe

Browse files
committed
Implement GString::substr() with ranges
1 parent fd4cd27 commit 5d7a7fe

File tree

5 files changed

+56
-4
lines changed

5 files changed

+56
-4
lines changed

godot-codegen/src/special_cases/special_cases.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,6 @@ pub fn is_builtin_method_exposed(builtin_ty: &TyName, godot_method_name: &str) -
241241
| ("String", "naturalnocasecmp_to")
242242
| ("String", "filecasecmp_to")
243243
| ("String", "filenocasecmp_to")
244-
| ("String", "substr")
245244
| ("String", "get_slice")
246245
| ("String", "get_slicec")
247246
| ("String", "get_slice_count")
@@ -347,7 +346,6 @@ pub fn is_builtin_method_exposed(builtin_ty: &TyName, godot_method_name: &str) -
347346
| ("StringName", "naturalnocasecmp_to")
348347
| ("StringName", "filecasecmp_to")
349348
| ("StringName", "filenocasecmp_to")
350-
| ("StringName", "substr")
351349
| ("StringName", "get_slice")
352350
| ("StringName", "get_slicec")
353351
| ("StringName", "get_slice_count")

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
66
*/
77

8+
use std::convert::Infallible;
9+
use std::ffi::c_char;
810
use std::fmt::Write;
9-
use std::{convert::Infallible, ffi::c_char, fmt, str::FromStr};
11+
use std::str::FromStr;
12+
use std::{fmt, ops};
1013

1114
use godot_ffi as sys;
1215
use sys::types::OpaqueString;
@@ -107,6 +110,13 @@ impl GString {
107110
}
108111
}
109112

113+
/// Returns a substring of this, as another `GString`.
114+
pub fn substr(&self, range: impl ops::RangeBounds<usize>) -> Self {
115+
let (from, len) = super::to_fromlen_pair(range);
116+
117+
self.as_inner().substr(from, len)
118+
}
119+
110120
/// Format a string using substitutions from an array or dictionary.
111121
///
112122
/// See Godot's [`String.format()`](https://docs.godotengine.org/en/stable/classes/class_string.html#class-string-method-format).

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ mod string_name;
1414

1515
use crate::meta::error::ConvertError;
1616
use crate::meta::{FromGodot, GodotConvert, ToGodot};
17+
use std::ops;
1718

1819
pub use gstring::*;
1920
pub use node_path::NodePath;
@@ -51,3 +52,25 @@ impl FromGodot for String {
5152
Ok(via.to_string())
5253
}
5354
}
55+
56+
// ----------------------------------------------------------------------------------------------------------------------------------------------
57+
58+
/// Returns a tuple of `(from, len)` from a Rust range.
59+
fn to_fromlen_pair<R>(range: R) -> (i64, i64)
60+
where
61+
R: ops::RangeBounds<usize>,
62+
{
63+
let from = match range.start_bound() {
64+
ops::Bound::Included(&n) => n as i64,
65+
ops::Bound::Excluded(&n) => (n as i64) + 1,
66+
ops::Bound::Unbounded => 0,
67+
};
68+
69+
let len = match range.end_bound() {
70+
ops::Bound::Included(&n) => ((n + 1) as i64) - from,
71+
ops::Bound::Excluded(&n) => (n as i64) - from,
72+
ops::Bound::Unbounded => -1,
73+
};
74+
75+
(from, len)
76+
}

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
66
*/
77

8-
use std::fmt;
8+
use std::{fmt, ops};
99

1010
use godot_ffi as sys;
1111
use sys::{ffi_methods, GodotFfi};
@@ -76,6 +76,16 @@ impl StringName {
7676
.expect("Godot hashes are uint32_t")
7777
}
7878

79+
// TODO unimplemented because it returns GString -- there must be an efficient way to substring interned string names?
80+
/*
81+
/// Returns a substring of this, as another `StringName`.
82+
pub fn substr(&self, range: impl ops::RangeBounds<usize>) -> Self {
83+
let (from, len) = super::from_len(range);
84+
85+
self.as_inner().substr(from, len)
86+
}
87+
*/
88+
7989
/// Format a string using substitutions from an array or dictionary.
8090
///
8191
/// The result is `GString` and not `StringName`.

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,14 @@ fn string_with_null() {
113113
assert_eq!(left, right);
114114
}
115115
}
116+
117+
#[itest]
118+
fn string_substr() {
119+
let string = GString::from("stable");
120+
assert_eq!(string.substr(..), "stable".into());
121+
assert_eq!(string.substr(1..), "table".into());
122+
assert_eq!(string.substr(..4), "stab".into());
123+
assert_eq!(string.substr(..=3), "stab".into());
124+
assert_eq!(string.substr(2..5), "abl".into());
125+
assert_eq!(string.substr(2..=4), "abl".into());
126+
}

0 commit comments

Comments
 (0)