Skip to content

Commit 18f94ac

Browse files
authored
Merge pull request #1393 from godot-rust/feature/array-functional-ops
Add `Array::functional_ops()`
2 parents bbd113a + 3832736 commit 18f94ac

File tree

9 files changed

+361
-58
lines changed

9 files changed

+361
-58
lines changed

godot-codegen/src/special_cases/special_cases.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,7 @@ pub fn is_builtin_method_deleted(_class_name: &TyName, method: &JsonBuiltinMetho
801801
/// Returns some generic type – such as `GenericArray` representing `Array<T>` – if method is marked as generic, `None` otherwise.
802802
///
803803
/// Usually required to initialize the return value and cache its type (see also https://github.com/godot-rust/gdext/pull/1357).
804+
#[rustfmt::skip]
804805
pub fn builtin_method_generic_ret(
805806
class_name: &TyName,
806807
method: &JsonBuiltinMethod,
@@ -809,9 +810,11 @@ pub fn builtin_method_generic_ret(
809810
class_name.rust_ty.to_string().as_str(),
810811
method.name.as_str(),
811812
) {
812-
("Array", "duplicate") | ("Array", "slice") => {
813-
Some(FnReturn::with_generic_builtin(RustTy::GenericArray))
814-
}
813+
| ("Array", "duplicate")
814+
| ("Array", "slice")
815+
| ("Array", "filter")
816+
817+
=> Some(FnReturn::with_generic_builtin(RustTy::GenericArray)),
815818
_ => None,
816819
}
817820
}

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

Lines changed: 38 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use std::{cmp, fmt};
1212
use godot_ffi as sys;
1313
use sys::{ffi_methods, interface_fn, GodotFfi};
1414

15+
use crate::builtin::iter::ArrayFunctionalOps;
1516
use crate::builtin::*;
1617
use crate::meta;
1718
use crate::meta::error::{ConvertError, FromGodotError, FromVariantError};
@@ -178,7 +179,7 @@ pub struct Array<T: ArrayElement> {
178179
}
179180

180181
/// Guard that can only call immutable methods on the array.
181-
struct ImmutableInnerArray<'a> {
182+
pub(super) struct ImmutableInnerArray<'a> {
182183
inner: inner::InnerArray<'a>,
183184
}
184185

@@ -608,6 +609,13 @@ impl<T: ArrayElement> Array<T> {
608609
}
609610
}
610611

612+
/// Access to Godot's functional-programming APIs based on callables.
613+
///
614+
/// Exposes Godot array methods such as `filter()`, `map()`, `reduce()` and many more. See return type docs.
615+
pub fn functional_ops(&self) -> ArrayFunctionalOps<'_, T> {
616+
ArrayFunctionalOps::new(self)
617+
}
618+
611619
/// Returns the minimum value contained in the array if all elements are of comparable types.
612620
///
613621
/// If the elements can't be compared or the array is empty, `None` is returned.
@@ -672,6 +680,8 @@ impl<T: ArrayElement> Array<T> {
672680
///
673681
/// Calling `bsearch` on an unsorted array results in unspecified behavior. Consider using `sort()` to ensure the sorting
674682
/// order is compatible with your callable's ordering.
683+
///
684+
/// See also: [`bsearch_by()`][Self::bsearch_by], [`functional_ops().bsearch_custom()`][ArrayFunctionalOps::bsearch_custom].
675685
pub fn bsearch(&self, value: impl AsArg<T>) -> usize {
676686
meta::arg_into_ref!(value: T);
677687

@@ -682,13 +692,15 @@ impl<T: ArrayElement> Array<T> {
682692
///
683693
/// The comparator function should return an ordering that indicates whether its argument is `Less`, `Equal` or `Greater` the desired value.
684694
/// For example, for an ascending-ordered array, a simple predicate searching for a constant value would be `|elem| elem.cmp(&4)`.
685-
/// See also [`slice::binary_search_by()`].
695+
/// This follows the design of [`slice::binary_search_by()`].
686696
///
687697
/// If the value is found, returns `Ok(index)` with its index. Otherwise, returns `Err(index)`, where `index` is the insertion index
688698
/// that would maintain sorting order.
689699
///
690-
/// Calling `bsearch_by` on an unsorted array results in unspecified behavior. Consider using [`sort_by()`] to ensure
691-
/// the sorting order is compatible with your callable's ordering.
700+
/// Calling `bsearch_by` on an unsorted array results in unspecified behavior. Consider using [`sort_unstable_by()`][Self::sort_unstable_by]
701+
/// to ensure the sorting order is compatible with your callable's ordering.
702+
///
703+
/// See also: [`bsearch()`][Self::bsearch], [`functional_ops().bsearch_custom()`][ArrayFunctionalOps::bsearch_custom].
692704
pub fn bsearch_by<F>(&self, mut func: F) -> Result<usize, usize>
693705
where
694706
F: FnMut(&T) -> cmp::Ordering + 'static,
@@ -712,7 +724,7 @@ impl<T: ArrayElement> Array<T> {
712724

713725
let debug_name = std::any::type_name::<F>();
714726
let index = Callable::with_scoped_fn(debug_name, godot_comparator, |pred| {
715-
self.bsearch_custom(ignored_value, pred)
727+
self.functional_ops().bsearch_custom(ignored_value, pred)
716728
});
717729

718730
if let Some(value_at_index) = self.get(index) {
@@ -724,22 +736,9 @@ impl<T: ArrayElement> Array<T> {
724736
Err(index)
725737
}
726738

727-
/// Finds the index of a value in a sorted array using binary search, with `Callable` custom predicate.
728-
///
729-
/// The callable `pred` takes two elements `(a, b)` and should return if `a < b` (strictly less).
730-
/// For a type-safe version, check out [`bsearch_by()`][Self::bsearch_by].
731-
///
732-
/// If the value is not present in the array, returns the insertion index that would maintain sorting order.
733-
///
734-
/// Calling `bsearch_custom` on an unsorted array results in unspecified behavior. Consider using `sort_custom()` to ensure
735-
/// the sorting order is compatible with your callable's ordering.
739+
#[deprecated = "Moved to `functional_ops().bsearch_custom()`"]
736740
pub fn bsearch_custom(&self, value: impl AsArg<T>, pred: &Callable) -> usize {
737-
meta::arg_into_ref!(value: T);
738-
739-
to_usize(
740-
self.as_inner()
741-
.bsearch_custom(&value.to_variant(), pred, true),
742-
)
741+
self.functional_ops().bsearch_custom(value, pred)
743742
}
744743

745744
/// Reverses the order of the elements in the array.
@@ -753,9 +752,11 @@ impl<T: ArrayElement> Array<T> {
753752
/// Sorts the array.
754753
///
755754
/// The sorting algorithm used is not [stable](https://en.wikipedia.org/wiki/Sorting_algorithm#Stability).
756-
/// This means that values considered equal may have their order changed when using `sort_unstable`. For most variant types,
755+
/// This means that values considered equal may have their order changed when using `sort_unstable()`. For most variant types,
757756
/// this distinction should not matter though.
758757
///
758+
/// See also: [`sort_unstable_by()`][Self::sort_unstable_by], [`sort_unstable_custom()`][Self::sort_unstable_custom].
759+
///
759760
/// _Godot equivalent: `Array.sort()`_
760761
#[doc(alias = "sort")]
761762
pub fn sort_unstable(&mut self) {
@@ -771,8 +772,10 @@ impl<T: ArrayElement> Array<T> {
771772
/// elements themselves would be achieved with `|a, b| a.cmp(b)`.
772773
///
773774
/// The sorting algorithm used is not [stable](https://en.wikipedia.org/wiki/Sorting_algorithm#Stability).
774-
/// This means that values considered equal may have their order changed when using `sort_unstable_by`. For most variant types,
775+
/// This means that values considered equal may have their order changed when using `sort_unstable_by()`. For most variant types,
775776
/// this distinction should not matter though.
777+
///
778+
/// See also: [`sort_unstable()`][Self::sort_unstable], [`sort_unstable_custom()`][Self::sort_unstable_custom].
776779
pub fn sort_unstable_by<F>(&mut self, mut func: F)
777780
where
778781
F: FnMut(&T, &T) -> cmp::Ordering,
@@ -795,14 +798,14 @@ impl<T: ArrayElement> Array<T> {
795798

796799
/// Sorts the array, using type-unsafe `Callable` comparator.
797800
///
798-
/// For a type-safe variant of this method, use [`sort_unstable_by()`][Self::sort_unstable_by].
799-
///
800801
/// The callable expects two parameters `(lhs, rhs)` and should return a bool `lhs < rhs`.
801802
///
802803
/// The sorting algorithm used is not [stable](https://en.wikipedia.org/wiki/Sorting_algorithm#Stability).
803-
/// This means that values considered equal may have their order changed when using `sort_unstable_custom`.For most variant types,
804+
/// This means that values considered equal may have their order changed when using `sort_unstable_custom()`. For most variant types,
804805
/// this distinction should not matter though.
805806
///
807+
/// Type-safe alternatives: [`sort_unstable()`][Self::sort_unstable] , [`sort_unstable_by()`][Self::sort_unstable_by].
808+
///
806809
/// _Godot equivalent: `Array.sort_custom()`_
807810
#[doc(alias = "sort_custom")]
808811
pub fn sort_unstable_custom(&mut self, func: &Callable) {
@@ -940,7 +943,7 @@ impl<T: ArrayElement> Array<T> {
940943
inner::InnerArray::from_outer_typed(self)
941944
}
942945

943-
fn as_inner(&self) -> ImmutableInnerArray<'_> {
946+
pub(super) fn as_inner(&self) -> ImmutableInnerArray<'_> {
944947
ImmutableInnerArray {
945948
// SAFETY: We can only read from the array.
946949
inner: unsafe { self.as_inner_mut() },
@@ -1634,21 +1637,25 @@ macro_rules! varray {
16341637
/// This macro creates a [slice](https://doc.rust-lang.org/std/primitive.slice.html) of `Variant` values.
16351638
///
16361639
/// # Examples
1637-
/// Variable number of arguments:
1640+
/// ## Variable number of arguments
16381641
/// ```no_run
16391642
/// # use godot::prelude::*;
16401643
/// let slice: &[Variant] = vslice![42, "hello", true];
1641-
///
16421644
/// let concat: GString = godot::global::str(slice);
16431645
/// ```
1644-
/// _(In practice, you might want to use [`godot_str!`][crate::global::godot_str] instead of `str()`.)_
1646+
/// _In practice, you might want to use [`godot_str!`][crate::global::godot_str] instead of `str()`._
16451647
///
1646-
/// Dynamic function call via reflection. NIL can still be passed inside `vslice!`, just use `Variant::nil()`.
1648+
/// ## Dynamic function call via reflection
1649+
/// NIL can still be passed inside `vslice!`, just use `Variant::nil()`.
16471650
/// ```no_run
16481651
/// # use godot::prelude::*;
16491652
/// # fn some_object() -> Gd<Object> { unimplemented!() }
16501653
/// let mut obj: Gd<Object> = some_object();
1651-
/// obj.call("some_method", vslice![Vector2i::new(1, 2), Variant::nil()]);
1654+
///
1655+
/// obj.call("some_method", vslice![
1656+
/// Vector2i::new(1, 2),
1657+
/// Variant::nil(),
1658+
/// ]);
16521659
/// ```
16531660
///
16541661
/// # See also

0 commit comments

Comments
 (0)