Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions godot-core/src/builtin/string/gstring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,21 @@ impl fmt::Debug for GString {
}
}

// ----------------------------------------------------------------------------------------------------------------------------------------------
// Comparison with Rust strings

// API design:
// * StringName and NodePath don't implement PartialEq<&str> yet, because they require allocation (convert to GString).
// == should ideally not allocate.
// * Reverse `impl PartialEq<GString> for &str` is not implemented now. Comparisons usually take the form of variable == "literal".
// Can be added later if there are good use-cases.

impl PartialEq<&str> for GString {
fn eq(&self, other: &&str) -> bool {
self.chars().iter().copied().eq(other.chars())
}
}

// ----------------------------------------------------------------------------------------------------------------------------------------------
// Conversion from/into Rust string-types

Expand Down
4 changes: 2 additions & 2 deletions itest/rust/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ fn collect_inputs() -> Vec<Input> {
push!(inputs; float, f64, 127.83156478);
push!(inputs; bool, bool, true);
push!(inputs; Color, Color, Color(0.7, 0.5, 0.3, 0.2), Color::from_rgba(0.7, 0.5, 0.3, 0.2));
push!(inputs; String, GString, "hello", "hello".into());
push!(inputs; String, GString, "hello", GString::from("hello"));
push!(inputs; StringName, StringName, &"hello", "hello".into());
pushs!(inputs; NodePath, NodePath, r#"^"hello""#, "hello".into(), true, true, None);
push!(inputs; Vector2, Vector2, Vector2(12.5, -3.5), Vector2::new(12.5, -3.5));
Expand Down Expand Up @@ -170,7 +170,7 @@ fn collect_inputs() -> Vec<Input> {
push_newtype!(inputs; float, NewF64(f64), 127.83156478);
push_newtype!(inputs; bool, NewBool(bool), true);
push_newtype!(inputs; Color, NewColor(Color), Color(0.7, 0.5, 0.3, 0.2), NewColor(Color::from_rgba(0.7, 0.5, 0.3, 0.2)));
push_newtype!(inputs; String, NewString(GString), "hello", NewString("hello".into()));
push_newtype!(inputs; String, NewString(GString), "hello", NewString(GString::from("hello")));
push_newtype!(inputs; StringName, NewStringName(StringName), &"hello", NewStringName("hello".into()));
push_newtype!(@s inputs; NodePath, NewNodePath(NodePath), r#"^"hello""#, NewNodePath("hello".into()));
push_newtype!(inputs; Vector2, NewVector2(Vector2), Vector2(12.5, -3.5), NewVector2(Vector2::new(12.5, -3.5)));
Expand Down
12 changes: 6 additions & 6 deletions itest/rust/src/builtin_tests/containers/packed_array_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,11 @@ fn packed_array_index() {
array.push("first");
array.push(&GString::from("second"));

assert_eq!(array[0], "first".into());
assert_eq!(array[1], "second".into());
assert_eq!(array[0], "first");
assert_eq!(array[1], "second");

array[0] = GString::from("begin");
assert_eq!(array[0], "begin".into());
assert_eq!(array[0], "begin");
}

#[itest]
Expand Down Expand Up @@ -202,7 +202,7 @@ fn packed_array_push() {
let mut strings = PackedStringArray::from(&[GString::from("a")]);
strings.push("b");
assert_eq!(strings.len(), 2);
assert_eq!(strings[1], "b".into());
assert_eq!(strings[1], "b");

fn test<T: Generator>() {
let mut array = PackedArray::<T>::new();
Expand Down Expand Up @@ -481,7 +481,7 @@ fn packed_array_as_slice() {
);

let empty = PackedStringArray::new();
assert_eq!(empty.as_slice(), &[]);
assert_eq!(empty.as_slice(), &[] as &[GString]); // Ambiguity due to GString==&str op. Could use is_empty() but this uses explicit type.
}

#[itest]
Expand All @@ -501,7 +501,7 @@ fn packed_array_as_mut_slice() {
);

let mut empty = PackedStringArray::new();
assert_eq!(empty.as_mut_slice(), &mut []);
assert_eq!(empty.as_mut_slice(), &mut [] as &mut [GString]);
}

// ----------------------------------------------------------------------------------------------------------------------------------------------
Expand Down
59 changes: 33 additions & 26 deletions itest/rust/src/builtin_tests/string/gstring_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ fn string_equality() {
assert_ne!(string, different);
}

#[itest]
fn string_eq_str() {
let gstring = GString::from("hello");
assert_eq!(gstring, "hello");
assert_ne!(gstring, "hallo");
}

#[itest]
fn string_ordering() {
let low = GString::from("Alpha");
Expand Down Expand Up @@ -130,12 +137,12 @@ fn string_with_null() {
#[itest]
fn string_substr() {
let string = GString::from("stable");
assert_eq!(string.substr(..), "stable".into());
assert_eq!(string.substr(1..), "table".into());
assert_eq!(string.substr(..4), "stab".into());
assert_eq!(string.substr(..=3), "stab".into());
assert_eq!(string.substr(2..5), "abl".into());
assert_eq!(string.substr(2..=4), "abl".into());
assert_eq!(string.substr(..), "stable");
assert_eq!(string.substr(1..), "table");
assert_eq!(string.substr(..4), "stab");
assert_eq!(string.substr(..=3), "stab");
assert_eq!(string.substr(2..5), "abl");
assert_eq!(string.substr(2..=4), "abl");
}

#[itest]
Expand Down Expand Up @@ -217,42 +224,42 @@ fn gstring_erase() {
let s = GString::from("Hello World");
assert_eq!(s.erase(..), GString::new());
assert_eq!(s.erase(4..4), s);
assert_eq!(s.erase(2..=2), "Helo World".into());
assert_eq!(s.erase(1..=3), "Ho World".into());
assert_eq!(s.erase(1..4), "Ho World".into());
assert_eq!(s.erase(..6), "World".into());
assert_eq!(s.erase(5..), "Hello".into());
assert_eq!(s.erase(2..=2), "Helo World");
assert_eq!(s.erase(1..=3), "Ho World");
assert_eq!(s.erase(1..4), "Ho World");
assert_eq!(s.erase(..6), "World");
assert_eq!(s.erase(5..), "Hello");
}

#[itest]
fn gstring_insert() {
let s = GString::from("H World");
assert_eq!(s.insert(1, "i"), "Hi World".into());
assert_eq!(s.insert(1, "ello"), "Hello World".into());
assert_eq!(s.insert(7, "."), "H World.".into());
assert_eq!(s.insert(0, "¿"), "¿H World".into());
assert_eq!(s.insert(1, "i"), "Hi World");
assert_eq!(s.insert(1, "ello"), "Hello World");
assert_eq!(s.insert(7, "."), "H World.");
assert_eq!(s.insert(0, "¿"), "¿H World");

// Special behavior in Godot, but maybe the idea is to allow large constants to mean "end".
assert_eq!(s.insert(123, "!"), "H World!".into());
assert_eq!(s.insert(123, "!"), "H World!");
}

#[itest]
fn gstring_pad() {
let s = GString::from("123");
assert_eq!(s.lpad(5, '0'), "00123".into());
assert_eq!(s.lpad(2, ' '), "123".into());
assert_eq!(s.lpad(4, ' '), " 123".into());
assert_eq!(s.lpad(5, '0'), "00123");
assert_eq!(s.lpad(2, ' '), "123");
assert_eq!(s.lpad(4, ' '), " 123");

assert_eq!(s.rpad(5, '+'), "123++".into());
assert_eq!(s.rpad(2, ' '), "123".into());
assert_eq!(s.rpad(4, ' '), "123 ".into());
assert_eq!(s.rpad(5, '+'), "123++");
assert_eq!(s.rpad(2, ' '), "123");
assert_eq!(s.rpad(4, ' '), "123 ");

let s = GString::from("123.456");
assert_eq!(s.pad_decimals(5), "123.45600".into());
assert_eq!(s.pad_decimals(2), "123.45".into()); // note: Godot rounds down
assert_eq!(s.pad_decimals(5), "123.45600");
assert_eq!(s.pad_decimals(2), "123.45"); // note: Godot rounds down

assert_eq!(s.pad_zeros(5), "00123.456".into());
assert_eq!(s.pad_zeros(2), "123.456".into());
assert_eq!(s.pad_zeros(5), "00123.456");
assert_eq!(s.pad_zeros(2), "123.456");
}

// Byte and C-string conversions.
Expand Down
4 changes: 2 additions & 2 deletions itest/rust/src/engine_tests/match_class_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ fn match_class_named_fallback_matched() {
// Named fallback with access to original object.
other => {
require_object(&other);
assert_eq!(other.get_class(), "Resource".into());
assert_eq!(other.get_class(), "Resource");
3
}
};
Expand All @@ -145,7 +145,7 @@ fn match_class_named_mut_fallback_matched() {
// Named fallback with access to original object.
mut other => {
require_mut_object(&mut other);
assert_eq!(other.get_class(), "Resource".into());
assert_eq!(other.get_class(), "Resource");
3
}
};
Expand Down
3 changes: 1 addition & 2 deletions itest/rust/src/engine_tests/utilities_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ fn utilities_str() {

let empty = str(&[]);

// TODO: implement GString==&str operator. Then look for "...".into() patterns and replace them.
assert_eq!(concat, "12 is a true number".into());
assert_eq!(concat, "12 is a true number");
assert_eq!(concat, godot_str!("{a}{b}{c}{d}"));
assert_eq!(empty, GString::new());
}
Expand Down
2 changes: 1 addition & 1 deletion itest/rust/src/object_tests/base_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ fn base_refcounted_weak_reference() {

// Call an API to ensure Base is functional.
let class_name = base_guard.get_class();
assert_eq!(class_name, "RefcBased".into());
assert_eq!(class_name, "RefcBased");
}

let final_refcount = obj.get_reference_count();
Expand Down
7 changes: 2 additions & 5 deletions itest/rust/src/object_tests/property_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,14 +414,11 @@ fn derive_property() {
fn enum_var_hint() {
let int_prop = <Behavior as Var>::var_hint();
assert_eq!(int_prop.hint, PropertyHint::ENUM);
assert_eq!(
int_prop.hint_string,
"Peaceful:0,Defend:1,Aggressive:7".into()
);
assert_eq!(int_prop.hint_string, "Peaceful:0,Defend:1,Aggressive:7");

let str_prop = <StrBehavior as Var>::var_hint();
assert_eq!(str_prop.hint, PropertyHint::ENUM);
assert_eq!(str_prop.hint_string, "Peaceful,Defend,Aggressive".into());
assert_eq!(str_prop.hint_string, "Peaceful,Defend,Aggressive");
}

#[derive(GodotClass)]
Expand Down
12 changes: 6 additions & 6 deletions itest/rust/src/register_tests/derive_godotconvert_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,12 @@ fn enum_stringy() {
roundtrip(EnumStringy::E);
roundtrip(EnumStringy::F);

assert_eq!(EnumStringy::A.to_godot(), "A".into());
assert_eq!(EnumStringy::B.to_godot(), "B".into());
assert_eq!(EnumStringy::C.to_godot(), "C".into());
assert_eq!(EnumStringy::D.to_godot(), "D".into());
assert_eq!(EnumStringy::E.to_godot(), "E".into());
assert_eq!(EnumStringy::F.to_godot(), "F".into());
assert_eq!(EnumStringy::A.to_godot(), "A");
assert_eq!(EnumStringy::B.to_godot(), "B");
assert_eq!(EnumStringy::C.to_godot(), "C");
assert_eq!(EnumStringy::D.to_godot(), "D");
assert_eq!(EnumStringy::E.to_godot(), "E");
assert_eq!(EnumStringy::F.to_godot(), "F");

// Rust-side discriminants.
assert_eq!(EnumStringy::A as isize, 0);
Expand Down
4 changes: 3 additions & 1 deletion itest/rust/src/register_tests/gdscript_ffi_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@

#![allow(dead_code)]

// While some of these lints are legitimate, no one cares for this generated code, and it's definitely not worth complicating the generator.
#[rustfmt::skip]
#[allow(clippy::partialeq_to_none)]
#[allow(clippy::partialeq_to_none)] // i == None -> i.is_none()
#[allow(clippy::cmp_owned)] // i == GString::from("hello") -> i == "hello"
pub mod gen_ffi {
include!(concat!(env!("OUT_DIR"), "/gen_ffi.rs"));
}
Loading