Replace with function with Function trait

This commit is contained in:
Héctor Ramón Jiménez 2025-02-11 10:36:45 +01:00
parent 080db34849
commit eab723866e
No known key found for this signature in database
GPG key ID: 7CC46565708259A7
7 changed files with 75 additions and 79 deletions

View file

@ -94,62 +94,59 @@ pub fn never<T>(never: std::convert::Infallible) -> T {
match never {}
}
/// Applies the given prefix value to the provided closure and returns
/// a new closure that takes the other argument.
/// A trait extension for binary functions (`Fn(A, B) -> O`).
///
/// This lets you partially "apply" a function—equivalent to currying,
/// but it only works with binary functions. If you want to apply an
/// arbitrary number of arguments, use the [`with!`] macro instead.
///
/// # When is this useful?
/// Sometimes you will want to identify the source or target
/// of some message in your user interface. This can be achieved through
/// normal means by defining a closure and moving the identifier
/// inside:
///
/// ```rust
/// # let element: Option<()> = Some(());
/// # enum Message { ButtonPressed(u32, ()) }
/// let id = 123;
///
/// # let _ = {
/// element.map(move |result| Message::ButtonPressed(id, result))
/// # };
/// ```
///
/// That's quite a mouthful. [`with()`] lets you write:
///
/// ```rust
/// # use iced_core::with;
/// # let element: Option<()> = Some(());
/// # enum Message { ButtonPressed(u32, ()) }
/// let id = 123;
///
/// # let _ = {
/// element.map(with(Message::ButtonPressed, id))
/// # };
/// ```
///
/// Effectively creating the same closure that partially applies
/// the `id` to the message—but much more concise!
pub fn with<T, R, O>(
mut f: impl FnMut(T, R) -> O,
prefix: T,
) -> impl FnMut(R) -> O
where
T: Copy,
{
move |result| f(prefix, result)
/// It enables you to use a bunch of nifty functional programming paradigms
/// that work well with iced.
pub trait Function<A, B, O> {
/// Applies the given first argument to a binary function and returns
/// a new function that takes the other argument.
///
/// This lets you partially "apply" a function—equivalent to currying,
/// but it only works with binary functions. If you want to apply an
/// arbitrary number of arguments, create a little struct for them.
///
/// # When is this useful?
/// Sometimes you will want to identify the source or target
/// of some message in your user interface. This can be achieved through
/// normal means by defining a closure and moving the identifier
/// inside:
///
/// ```rust
/// # let element: Option<()> = Some(());
/// # enum Message { ButtonPressed(u32, ()) }
/// let id = 123;
///
/// # let _ = {
/// element.map(move |result| Message::ButtonPressed(id, result))
/// # };
/// ```
///
/// That's quite a mouthful. [`with`] lets you write:
///
/// ```rust
/// # use iced_core::Function;
/// # let element: Option<()> = Some(());
/// # enum Message { ButtonPressed(u32, ()) }
/// let id = 123;
///
/// # let _ = {
/// element.map(Message::ButtonPressed.with(id))
/// # };
/// ```
///
/// Effectively creating the same closure that partially applies
/// the `id` to the message—but much more concise!
fn with(self, prefix: A) -> impl Fn(B) -> O;
}
/// Applies the given prefix values to the provided closure in the first
/// argument and returns a new closure that takes its last argument.
///
/// This is a variadic version of [`with()`] which works with any number of
/// arguments.
#[macro_export]
macro_rules! with {
($f:expr, $($x:expr),+ $(,)?) => {
move |result| $f($($x),+, result)
};
impl<F, A, B, O> Function<A, B, O> for F
where
F: Fn(A, B) -> O,
Self: Sized,
A: Copy,
{
fn with(self, prefix: A) -> impl Fn(B) -> O {
move |result| self(prefix, result)
}
}