From 930b5a7483d69bf991c498eca5ecf28d0cff7fdc Mon Sep 17 00:00:00 2001 From: 0awful Date: Tue, 9 Jan 2024 22:57:18 -0800 Subject: [PATCH] #310-array-builtins --- godot-core/src/builtin/array.rs | 44 ++++++++++++++++--- .../builtin_tests/containers/array_test.rs | 34 +++++++++++--- 2 files changed, 67 insertions(+), 11 deletions(-) diff --git a/godot-core/src/builtin/array.rs b/godot-core/src/builtin/array.rs index 922c772a2..74cd596f6 100644 --- a/godot-core/src/builtin/array.rs +++ b/godot-core/src/builtin/array.rs @@ -135,10 +135,23 @@ impl Array { /// Note: The sorting algorithm used is not /// [stable](https://en.wikipedia.org/wiki/Sorting_algorithm#Stability). This means that values /// considered equal may have their order changed when using `sort_unstable`. + #[doc(alias = "sort")] pub fn sort_unstable(&mut self) { self.as_inner().sort(); } + /// Sorts the array. + /// + /// Uses the provided `Callable` to determine ordering. + /// + /// Note: The sorting algorithm used is not [stable](https://en.wikipedia.org/wiki/Sorting_algorithm#Stability). + /// This means that values considered equal may have their order changed when using + /// `sort_unstable`. + #[doc(alias = "sort_custom")] + pub fn sort_unstable_custom(&mut self, func: Callable) { + self.as_inner().sort_custom(func); + } + /// Shuffles the array such that the items will have a random order. This method uses the /// global random number generator common to methods such as `randi`. Call `randomize` to /// ensure that a new seed will be used each time if you want non-reproducible shuffling. @@ -492,17 +505,36 @@ impl Array { } impl Array { - /// Finds the index of an existing value in a sorted array using binary search. Equivalent of - /// `bsearch` in GDScript. + /// Finds the index of an existing value in a sorted array using binary search. + /// Equivalent of `bsearch` in GDScript. /// - /// If the value is not present in the array, returns the insertion index that would maintain - /// sorting order. + /// If the value is not present in the array, returns the insertion index that + /// would maintain sorting order. /// - /// Calling `binary_search` on an unsorted array results in unspecified behavior. - pub fn binary_search(&self, value: &T) -> usize { + /// Calling `bsearch` on an unsorted array results in unspecified behavior. + pub fn bsearch(&self, value: &T) -> usize { to_usize(self.as_inner().bsearch(value.to_variant(), true)) } + /// Finds the index of an existing value in a sorted array using binary search. + /// Equivalent of `bsearch_custom` in GDScript. + /// + /// Takes a `Callable` and uses the return value of it to perform binary search. + /// + /// If the value is not present in the array, returns the insertion index that + /// would maintain sorting order. + /// + /// Calling `bsearch_custom` on an unsorted array results in unspecified behavior. + /// + /// Consider using `sort_custom()` to ensure the sorting order is compatible with + /// your callable's ordering + pub fn bsearch_custom(&self, value: &T, func: Callable) -> usize { + to_usize( + self.as_inner() + .bsearch_custom(value.to_variant(), func, true), + ) + } + /// Returns the number of times a value is in the array. pub fn count(&self, value: &T) -> usize { to_usize(self.as_inner().count(value.to_variant())) diff --git a/itest/rust/src/builtin_tests/containers/array_test.rs b/itest/rust/src/builtin_tests/containers/array_test.rs index 70ccd19f7..f38457626 100644 --- a/itest/rust/src/builtin_tests/containers/array_test.rs +++ b/itest/rust/src/builtin_tests/containers/array_test.rs @@ -200,11 +200,11 @@ fn array_first_last() { fn array_binary_search() { let array = array![1, 3]; - assert_eq!(array.binary_search(&0), 0); - assert_eq!(array.binary_search(&1), 0); - assert_eq!(array.binary_search(&2), 1); - assert_eq!(array.binary_search(&3), 1); - assert_eq!(array.binary_search(&4), 2); + assert_eq!(array.bsearch(&0), 0); + assert_eq!(array.bsearch(&1), 0); + assert_eq!(array.bsearch(&2), 1); + assert_eq!(array.bsearch(&3), 1); + assert_eq!(array.bsearch(&4), 2); } #[itest] @@ -473,6 +473,30 @@ fn array_should_format_with_display() { assert_eq!(format!("{a}"), "[]"); } +#[itest] +#[cfg(since_api = "4.2")] +fn array_sort_custom() { + let mut a = array![1, 2, 3, 4]; + let func = Callable::from_fn("sort backwards", |args: &[&Variant]| { + let res = i32::from_variant(args[0]) > i32::from_variant(args[1]); + Ok(Variant::from(res)) + }); + a.sort_unstable_custom(func); + assert_eq!(a, array![4, 3, 2, 1]); +} + +#[itest] +#[cfg(since_api = "4.2")] +fn array_binary_search_custom() { + let a = array![5, 4, 2, 1]; + let func = Callable::from_fn("sort backwards", |args: &[&Variant]| { + let res = i32::from_variant(args[0]) > i32::from_variant(args[1]); + Ok(Variant::from(res)) + }); + assert_eq!(a.bsearch_custom(&1, func.clone()), 3); + assert_eq!(a.bsearch_custom(&3, func), 2); +} + #[derive(GodotClass, Debug)] #[class(init, base=RefCounted)] struct ArrayTest;