Skip to content

Commit 94ae1ae

Browse files
bors[bot]lilizoey
andauthored
Merge #233
233: Refactor `GodotString`, `NodePath`, and `StringName` r=lilizoey a=lilizoey Creates a new module in `builtin` that contains all the string-related modules. Make all the string-files look more similar where it made sense. And add things that only existed in one of the three but not the others, such as: `Hash` impl (now using godot's hashing), new-constructor, conversions. Added pass-by-value From impls in addition to pass-by-reference From impls, so we can do just ```rs let node_path: NodePath = string.into(); ``` instead of needing to do ```rs let node_path: NodePath = NodePath::from(&string); ``` Moves `String`-specific stuff into `builtin/string/mod.rs` and renamed `string.rs` to `godot_string.rs`. And adds a `VariantMetadata` impl for `String`. Adds some more tests to test all the types a bit more extensively. Since this is gonna conflict with #231 (as i added some stuff to StringName there) i wanna wait with merging this until that is merged. but otherwise the PR is ready to be merged. Co-authored-by: Lili Zoey <[email protected]>
2 parents 21f95f7 + 4c79b2b commit 94ae1ae

File tree

13 files changed

+500
-178
lines changed

13 files changed

+500
-178
lines changed

godot-core/src/builtin/macros.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,17 +107,27 @@ macro_rules! impl_builtin_traits_inner {
107107
}
108108
}
109109
};
110+
111+
112+
// Requires a `hash` function.
113+
( Hash for $Type:ty ) => {
114+
impl std::hash::Hash for $Type {
115+
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
116+
self.hash().hash(state)
117+
}
118+
}
119+
};
110120
}
111121

112122
macro_rules! impl_builtin_traits {
113123
(
114124
for $Type:ty {
115-
$( $Trait:ident => $gd_method:ident; )*
125+
$( $Trait:ident $(=> $gd_method:ident)?; )*
116126
}
117127
) => (
118128
$(
119129
impl_builtin_traits_inner! {
120-
$Trait for $Type => $gd_method
130+
$Trait for $Type $(=> $gd_method)?
121131
}
122132
)*
123133
)

godot-core/src/builtin/mod.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ pub use callable::*;
4242
pub use color::*;
4343
pub use dictionary_inner::Dictionary;
4444
pub use math::*;
45-
pub use node_path::*;
4645
pub use others::*;
4746
pub use packed_array::*;
4847
pub use plane::*;
@@ -52,7 +51,6 @@ pub use rect2::*;
5251
pub use rect2i::*;
5352
pub use rid::*;
5453
pub use string::*;
55-
pub use string_name::*;
5654
pub use transform2d::*;
5755
pub use transform3d::*;
5856
pub use variant::*;
@@ -95,7 +93,6 @@ mod callable;
9593
mod color;
9694
mod glam_helpers;
9795
mod math;
98-
mod node_path;
9996
mod others;
10097
mod packed_array;
10198
mod plane;
@@ -105,8 +102,6 @@ mod rect2;
105102
mod rect2i;
106103
mod rid;
107104
mod string;
108-
mod string_chars;
109-
mod string_name;
110105
mod transform2d;
111106
mod transform3d;
112107
mod variant;

godot-core/src/builtin/string.rs renamed to godot-core/src/builtin/string/godot_string.rs

Lines changed: 84 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,19 @@ use godot_ffi as sys;
1010
use sys::types::OpaqueString;
1111
use sys::{ffi_methods, interface_fn, GodotFfi};
1212

13-
use super::{
14-
string_chars::validate_unicode_scalar_sequence, FromVariant, ToVariant, Variant,
15-
VariantConversionError,
16-
};
13+
use crate::builtin::inner;
1714

15+
use super::string_chars::validate_unicode_scalar_sequence;
16+
use super::{NodePath, StringName};
17+
18+
/// Godot's reference counted string type.
1819
#[repr(C, align(8))]
1920
pub struct GodotString {
2021
opaque: OpaqueString,
2122
}
2223

2324
impl GodotString {
25+
/// Construct a new empty GodotString.
2426
pub fn new() -> Self {
2527
Self::default()
2628
}
@@ -29,12 +31,12 @@ impl GodotString {
2931
Self { opaque }
3032
}
3133

32-
ffi_methods! {
33-
type sys::GDExtensionStringPtr = *mut Opaque;
34-
35-
fn from_string_sys = from_sys;
36-
fn from_string_sys_init = from_sys_init;
37-
fn string_sys = sys;
34+
/// Returns a 32-bit integer hash value representing the string.
35+
pub fn hash(&self) -> u32 {
36+
self.as_inner()
37+
.hash()
38+
.try_into()
39+
.expect("Godot hashes are uint32_t")
3840
}
3941

4042
/// Move `self` into a system pointer. This transfers ownership and thus does not call the destructor.
@@ -83,6 +85,19 @@ impl GodotString {
8385
}
8486
std::slice::from_raw_parts(ptr as *const char, len as usize)
8587
}
88+
89+
ffi_methods! {
90+
type sys::GDExtensionStringPtr = *mut Opaque;
91+
92+
fn from_string_sys = from_sys;
93+
fn from_string_sys_init = from_sys_init;
94+
fn string_sys = sys;
95+
}
96+
97+
#[doc(hidden)]
98+
pub fn as_inner(&self) -> inner::InnerString {
99+
inner::InnerString::from_outer(self)
100+
}
86101
}
87102

88103
// SAFETY:
@@ -122,9 +137,28 @@ impl_builtin_traits! {
122137
Drop => string_destroy;
123138
Eq => string_operator_equal;
124139
Ord => string_operator_less;
140+
Hash;
141+
}
142+
}
143+
144+
impl fmt::Display for GodotString {
145+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
146+
let s: String = self.chars_checked().iter().collect();
147+
f.write_str(s.as_str())
148+
}
149+
}
150+
151+
/// Uses literal syntax from GDScript: `"string"`
152+
impl fmt::Debug for GodotString {
153+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154+
let s = String::from(self);
155+
write!(f, "\"{s}\"")
125156
}
126157
}
127158

159+
// ----------------------------------------------------------------------------------------------------------------------------------------------
160+
// Conversion from/into rust string-types
161+
128162
impl<S> From<S> for GodotString
129163
where
130164
S: AsRef<str>,
@@ -162,7 +196,14 @@ impl From<&GodotString> for String {
162196
}
163197
}
164198

165-
// TODO From<&NodePath> + test
199+
impl From<GodotString> for String {
200+
/// Converts this `GodotString` to a `String`.
201+
///
202+
/// This is identical to `String::from(&string)`, and as such there is no performance benefit.
203+
fn from(string: GodotString) -> Self {
204+
Self::from(&string)
205+
}
206+
}
166207

167208
impl FromStr for GodotString {
168209
type Err = Infallible;
@@ -172,49 +213,47 @@ impl FromStr for GodotString {
172213
}
173214
}
174215

175-
impl fmt::Display for GodotString {
176-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177-
let s = String::from(self);
178-
f.write_str(s.as_str())
179-
}
180-
}
181-
182-
/// Uses literal syntax from GDScript: `"string"`
183-
impl fmt::Debug for GodotString {
184-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185-
let s = String::from(self);
186-
write!(f, "\"{s}\"")
187-
}
188-
}
216+
// ----------------------------------------------------------------------------------------------------------------------------------------------
217+
// Conversion from other Godot string-types
189218

190-
impl ToVariant for &str {
191-
fn to_variant(&self) -> Variant {
192-
GodotString::from(*self).to_variant()
219+
impl From<&StringName> for GodotString {
220+
fn from(string: &StringName) -> Self {
221+
unsafe {
222+
Self::from_sys_init_default(|self_ptr| {
223+
let ctor = sys::builtin_fn!(string_from_string_name);
224+
let args = [string.sys_const()];
225+
ctor(self_ptr, args.as_ptr());
226+
})
227+
}
193228
}
194229
}
195230

196-
impl ToVariant for String {
197-
fn to_variant(&self) -> Variant {
198-
GodotString::from(self).to_variant()
231+
impl From<StringName> for GodotString {
232+
/// Converts this `StringName` to a `GodotString`.
233+
///
234+
/// This is identical to `GodotString::from(&string_name)`, and as such there is no performance benefit.
235+
fn from(string_name: StringName) -> Self {
236+
Self::from(&string_name)
199237
}
200238
}
201239

202-
impl FromVariant for String {
203-
fn try_from_variant(variant: &Variant) -> Result<Self, VariantConversionError> {
204-
Ok(GodotString::try_from_variant(variant)?.to_string())
240+
impl From<&NodePath> for GodotString {
241+
fn from(path: &NodePath) -> Self {
242+
unsafe {
243+
Self::from_sys_init_default(|self_ptr| {
244+
let ctor = sys::builtin_fn!(string_from_node_path);
245+
let args = [path.sys_const()];
246+
ctor(self_ptr, args.as_ptr());
247+
})
248+
}
205249
}
206250
}
207251

208-
// While this is a nice optimisation for ptrcalls, it's not easily possible
209-
// to pass in &GodotString when doing varcalls.
210-
/*
211-
impl PtrCall for &GodotString {
212-
unsafe fn from_ptr_call_arg(arg: *const godot_ffi::GDExtensionTypePtr) -> Self {
213-
&*(*arg as *const GodotString)
214-
}
215-
216-
unsafe fn to_ptr_call_arg(self, arg: godot_ffi::GDExtensionTypePtr) {
217-
std::ptr::write(arg as *mut GodotString, self.clone());
252+
impl From<NodePath> for GodotString {
253+
/// Converts this `NodePath` to a `GodotString`.
254+
///
255+
/// This is identical to `GodotString::from(&path)`, and as such there is no performance benefit.
256+
fn from(path: NodePath) -> Self {
257+
Self::from(&path)
218258
}
219259
}
220-
*/
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this
4+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
5+
*/
6+
7+
#![macro_use]
8+
9+
macro_rules! impl_rust_string_conv {
10+
($Ty:ty) => {
11+
impl<S> From<S> for $Ty
12+
where
13+
S: AsRef<str>,
14+
{
15+
fn from(string: S) -> Self {
16+
let intermediate = GodotString::from(string.as_ref());
17+
Self::from(&intermediate)
18+
}
19+
}
20+
21+
impl From<&$Ty> for String {
22+
fn from(string: &$Ty) -> Self {
23+
let intermediate = GodotString::from(string);
24+
Self::from(&intermediate)
25+
}
26+
}
27+
28+
impl From<$Ty> for String {
29+
fn from(string: $Ty) -> Self {
30+
Self::from(&string)
31+
}
32+
}
33+
34+
impl std::str::FromStr for $Ty {
35+
type Err = std::convert::Infallible;
36+
37+
fn from_str(string: &str) -> Result<Self, Self::Err> {
38+
Ok(Self::from(string))
39+
}
40+
}
41+
};
42+
}

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

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this
4+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
5+
*/
6+
7+
//! Godot-types that are Strings.
8+
9+
mod godot_string;
10+
mod macros;
11+
mod node_path;
12+
mod string_chars;
13+
mod string_name;
14+
15+
use godot_ffi::VariantType;
16+
pub use godot_string::*;
17+
pub use node_path::*;
18+
pub use string_name::*;
19+
20+
use super::{meta::VariantMetadata, FromVariant, ToVariant, Variant, VariantConversionError};
21+
22+
impl ToVariant for &str {
23+
fn to_variant(&self) -> Variant {
24+
GodotString::from(*self).to_variant()
25+
}
26+
}
27+
28+
impl ToVariant for String {
29+
fn to_variant(&self) -> Variant {
30+
GodotString::from(self).to_variant()
31+
}
32+
}
33+
34+
impl FromVariant for String {
35+
fn try_from_variant(variant: &Variant) -> Result<Self, VariantConversionError> {
36+
Ok(GodotString::try_from_variant(variant)?.to_string())
37+
}
38+
}
39+
40+
impl VariantMetadata for String {
41+
fn variant_type() -> VariantType {
42+
VariantType::String
43+
}
44+
}

0 commit comments

Comments
 (0)