Skip to content

Commit 7122f82

Browse files
committed
Implement Array::sort_unstable_by()
1 parent af83229 commit 7122f82

File tree

2 files changed

+70
-27
lines changed

2 files changed

+70
-27
lines changed

godot-core/src/builtin/collections/array.rs

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -651,7 +651,7 @@ impl<T: ArrayElement> Array<T> {
651651
let ignored_value = <T as ParamType>::owned_to_arg(ignored_value);
652652

653653
let godot_comparator = |args: &[&Variant]| {
654-
let value = T::from_variant(&args[0]);
654+
let value = T::from_variant(args[0]);
655655
let is_less = matches!(func(&value), cmp::Ordering::Less);
656656

657657
Ok(is_less.to_variant())
@@ -697,20 +697,55 @@ impl<T: ArrayElement> Array<T> {
697697

698698
/// Sorts the array.
699699
///
700-
/// Note: The sorting algorithm used is not [stable](https://en.wikipedia.org/wiki/Sorting_algorithm#Stability).
701-
/// This means that values considered equal may have their order changed when using `sort_unstable`.
700+
/// The sorting algorithm used is not [stable](https://en.wikipedia.org/wiki/Sorting_algorithm#Stability).
701+
/// This means that values considered equal may have their order changed when using `sort_unstable`. For most variant types,
702+
/// this distinction should not matter though.
703+
///
704+
/// _Godot equivalent: `Array.sort()`_
702705
#[doc(alias = "sort")]
703706
pub fn sort_unstable(&mut self) {
704707
// SAFETY: We do not write any values that don't already exist in the array, so all values have the correct type.
705708
unsafe { self.as_inner_mut() }.sort();
706709
}
707710

708-
/// Sorts the array.
711+
/// Sorts the array, using a type-safe comparator.
712+
///
713+
/// The predicate expects two parameters `(a, b)` and should return an ordering relation. For example, simple ascending ordering of the
714+
/// elements themselves would be achieved with `|a, b| a.cmp(b)`.
715+
///
716+
/// The sorting algorithm used is not [stable](https://en.wikipedia.org/wiki/Sorting_algorithm#Stability).
717+
/// This means that values considered equal may have their order changed when using `sort_unstable_by`. For most variant types,
718+
/// this distinction should not matter though.
719+
#[cfg(since_api = "4.2")]
720+
pub fn sort_unstable_by<F>(&mut self, mut func: F)
721+
where
722+
F: FnMut(&T, &T) -> cmp::Ordering,
723+
{
724+
let godot_comparator = |args: &[&Variant]| {
725+
let lhs = T::from_variant(args[0]);
726+
let rhs = T::from_variant(args[1]);
727+
let is_less = matches!(func(&lhs, &rhs), cmp::Ordering::Less);
728+
729+
Ok(is_less.to_variant())
730+
};
731+
732+
let debug_name = std::any::type_name::<F>();
733+
Callable::with_scoped_fn(debug_name, godot_comparator, |pred| {
734+
self.sort_unstable_custom(pred)
735+
});
736+
}
737+
738+
/// Sorts the array, using type-unsafe `Callable` comparator.
739+
///
740+
/// For a type-safe variant of this method, use [`sort_unstable_by()`][Self::sort_unstable_by].
741+
///
742+
/// The callable expects two parameters `(lhs, rhs)` and should return a bool `lhs < rhs`.
709743
///
710-
/// Uses the provided `Callable` to determine ordering.
744+
/// The sorting algorithm used is not [stable](https://en.wikipedia.org/wiki/Sorting_algorithm#Stability).
745+
/// This means that values considered equal may have their order changed when using `sort_unstable_custom`.For most variant types,
746+
/// this distinction should not matter though.
711747
///
712-
/// Note: The sorting algorithm used is not [stable](https://en.wikipedia.org/wiki/Sorting_algorithm#Stability).
713-
/// This means that values considered equal may have their order changed when using `sort_unstable_custom`.
748+
/// _Godot equivalent: `Array.sort_custom()`_
714749
#[doc(alias = "sort_custom")]
715750
pub fn sort_unstable_custom(&mut self, func: &Callable) {
716751
// SAFETY: We do not write any values that don't already exist in the array, so all values have the correct type.

itest/rust/src/builtin_tests/containers/array_test.rs

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -197,17 +197,6 @@ fn array_first_last() {
197197
assert_eq!(empty_array.back(), None);
198198
}
199199

200-
#[itest]
201-
fn array_binary_search() {
202-
let array = array![1, 3];
203-
204-
assert_eq!(array.bsearch(0), 0);
205-
assert_eq!(array.bsearch(1), 0);
206-
assert_eq!(array.bsearch(2), 1);
207-
assert_eq!(array.bsearch(3), 1);
208-
assert_eq!(array.bsearch(4), 2);
209-
}
210-
211200
#[itest]
212201
fn array_find() {
213202
let array = array![1, 2, 1];
@@ -298,13 +287,6 @@ fn array_extend() {
298287
assert_eq!(array, array![1, 2, 3, 4]);
299288
}
300289

301-
#[itest]
302-
fn array_sort() {
303-
let mut array = array![2, 1];
304-
array.sort_unstable();
305-
assert_eq!(array, array![1, 2]);
306-
}
307-
308290
#[itest]
309291
fn array_reverse() {
310292
let mut array = array![1, 2];
@@ -474,16 +456,42 @@ fn array_should_format_with_display() {
474456
assert_eq!(format!("{a}"), "[]");
475457
}
476458

459+
#[itest]
460+
fn array_sort_unstable() {
461+
let mut array = array![2, 1];
462+
array.sort_unstable();
463+
assert_eq!(array, array![1, 2]);
464+
}
465+
466+
#[itest]
467+
#[cfg(since_api = "4.2")]
468+
fn array_sort_unstable_by() {
469+
let mut array: Array<i32> = array![2, 1, 4, 3];
470+
array.sort_unstable_by(|a, b| a.cmp(b));
471+
assert_eq!(array, array![1, 2, 3, 4]);
472+
}
473+
477474
#[itest]
478475
#[cfg(since_api = "4.2")]
479-
fn array_sort_custom() {
476+
fn array_sort_unstable_custom() {
480477
let mut a = array![1, 2, 3, 4];
481478
let func = backwards_sort_callable();
482479
a.sort_unstable_custom(&func);
483480
assert_eq!(a, array![4, 3, 2, 1]);
484481
}
485482

486-
#[itest(focus)]
483+
#[itest]
484+
fn array_bsearch() {
485+
let array = array![1, 3];
486+
487+
assert_eq!(array.bsearch(0), 0);
488+
assert_eq!(array.bsearch(1), 0);
489+
assert_eq!(array.bsearch(2), 1);
490+
assert_eq!(array.bsearch(3), 1);
491+
assert_eq!(array.bsearch(4), 2);
492+
}
493+
494+
#[itest]
487495
#[cfg(since_api = "4.2")]
488496
fn array_bsearch_by() {
489497
let a: Array<i32> = array![1, 2, 4, 5];

0 commit comments

Comments
 (0)