Skip to content

Commit

Permalink
Merge pull request #561 from 0awful/#310-array
Browse files Browse the repository at this point in the history
#310 - Array builtin completeness
  • Loading branch information
Bromeon authored Jan 13, 2024
2 parents e3b61cc + 930b5a7 commit 0aa07d9
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 11 deletions.
44 changes: 38 additions & 6 deletions godot-core/src/builtin/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,23 @@ impl<T: GodotType> Array<T> {
/// 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.
Expand Down Expand Up @@ -492,17 +505,36 @@ impl<T: GodotType + FromGodot> Array<T> {
}

impl<T: GodotType + ToGodot> Array<T> {
/// 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()))
Expand Down
34 changes: 29 additions & 5 deletions itest/rust/src/builtin_tests/containers/array_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 0aa07d9

Please sign in to comment.