summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector@hecrj.dev>2025-02-11 10:36:45 +0100
committerLibravatar Héctor Ramón Jiménez <hector@hecrj.dev>2025-02-11 10:36:45 +0100
commiteab723866e1dc94ebd6d7c5c0c3ef191c80bcf59 (patch)
tree2b5a476f9da5155fd13e68957a9bbf3e3ab352a1
parent080db348495f6e92f13391d3b222c5a2769b5fc1 (diff)
downloadiced-eab723866e1dc94ebd6d7c5c0c3ef191c80bcf59.tar.gz
iced-eab723866e1dc94ebd6d7c5c0c3ef191c80bcf59.tar.bz2
iced-eab723866e1dc94ebd6d7c5c0c3ef191c80bcf59.zip
Replace `with` function with `Function` trait
-rw-r--r--core/src/lib.rs107
-rw-r--r--examples/download_progress/src/main.rs4
-rw-r--r--examples/gallery/src/main.rs6
-rw-r--r--examples/game_of_life/src/main.rs14
-rw-r--r--examples/multi_window/src/main.rs8
-rw-r--r--examples/todos/src/main.rs9
-rw-r--r--src/lib.rs6
7 files changed, 75 insertions, 79 deletions
diff --git a/core/src/lib.rs b/core/src/lib.rs
index a5540787..cd05cb25 100644
--- a/core/src/lib.rs
+++ b/core/src/lib.rs
@@ -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)
+ }
}
diff --git a/examples/download_progress/src/main.rs b/examples/download_progress/src/main.rs
index 9b316f52..8082eccd 100644
--- a/examples/download_progress/src/main.rs
+++ b/examples/download_progress/src/main.rs
@@ -4,7 +4,7 @@ use download::download;
use iced::task;
use iced::widget::{button, center, column, progress_bar, text, Column};
-use iced::{with, Center, Element, Right, Task};
+use iced::{Center, Element, Function, Right, Task};
pub fn main() -> iced::Result {
iced::application(
@@ -52,7 +52,7 @@ impl Example {
let task = download.start();
- task.map(with(Message::DownloadUpdated, index))
+ task.map(Message::DownloadUpdated.with(index))
}
Message::DownloadUpdated(id, update) => {
if let Some(download) =
diff --git a/examples/gallery/src/main.rs b/examples/gallery/src/main.rs
index 0ed2a862..abafaf2d 100644
--- a/examples/gallery/src/main.rs
+++ b/examples/gallery/src/main.rs
@@ -14,7 +14,7 @@ use iced::widget::{
};
use iced::window;
use iced::{
- color, with, Animation, ContentFit, Element, Fill, Subscription, Task,
+ color, Animation, ContentFit, Element, Fill, Function, Subscription, Task,
Theme,
};
@@ -100,8 +100,8 @@ impl Gallery {
width: Preview::WIDTH,
height: Preview::HEIGHT,
}),
- with(Message::BlurhashDecoded, id),
- with(Message::ThumbnailDownloaded, id),
+ Message::BlurhashDecoded.with(id),
+ Message::ThumbnailDownloaded.with(id),
)
}
Message::ImageDownloaded(Ok(rgba)) => {
diff --git a/examples/game_of_life/src/main.rs b/examples/game_of_life/src/main.rs
index dec3df7f..9516f832 100644
--- a/examples/game_of_life/src/main.rs
+++ b/examples/game_of_life/src/main.rs
@@ -9,7 +9,7 @@ use iced::time::{self, milliseconds};
use iced::widget::{
button, checkbox, column, container, pick_list, row, slider, text,
};
-use iced::{Center, Element, Fill, Subscription, Task, Theme};
+use iced::{Center, Element, Fill, Function, Subscription, Task, Theme};
pub fn main() -> iced::Result {
tracing_subscriber::fmt::init();
@@ -37,7 +37,7 @@ struct GameOfLife {
#[derive(Debug, Clone)]
enum Message {
- Grid(grid::Message, usize),
+ Grid(usize, grid::Message),
Tick,
TogglePlayback,
ToggleGrid(bool),
@@ -61,7 +61,7 @@ impl GameOfLife {
fn update(&mut self, message: Message) -> Task<Message> {
match message {
- Message::Grid(message, version) => {
+ Message::Grid(version, message) => {
if version == self.version {
self.grid.update(message);
}
@@ -78,9 +78,7 @@ impl GameOfLife {
let version = self.version;
- return Task::perform(task, move |message| {
- Message::Grid(message, version)
- });
+ return Task::perform(task, Message::Grid.with(version));
}
}
Message::TogglePlayback => {
@@ -129,9 +127,7 @@ impl GameOfLife {
);
let content = column![
- self.grid
- .view()
- .map(move |message| Message::Grid(message, version)),
+ self.grid.view().map(Message::Grid.with(version)),
controls,
]
.height(Fill);
diff --git a/examples/multi_window/src/main.rs b/examples/multi_window/src/main.rs
index f9021c8d..8cec9d4c 100644
--- a/examples/multi_window/src/main.rs
+++ b/examples/multi_window/src/main.rs
@@ -3,7 +3,9 @@ use iced::widget::{
text_input,
};
use iced::window;
-use iced::{Center, Element, Fill, Subscription, Task, Theme, Vector};
+use iced::{
+ Center, Element, Fill, Function, Subscription, Task, Theme, Vector,
+};
use std::collections::BTreeMap;
@@ -169,7 +171,7 @@ impl Window {
let scale_input = column![
text("Window scale factor:"),
text_input("Window Scale", &self.scale_input)
- .on_input(move |msg| { Message::ScaleInputChanged(id, msg) })
+ .on_input(Message::ScaleInputChanged.with(id))
.on_submit(Message::ScaleChanged(
id,
self.scale_input.to_string()
@@ -179,7 +181,7 @@ impl Window {
let title_input = column![
text("Window title:"),
text_input("Window Title", &self.title)
- .on_input(move |msg| { Message::TitleChanged(id, msg) })
+ .on_input(Message::TitleChanged.with(id))
.id(format!("input-{id}"))
];
diff --git a/examples/todos/src/main.rs b/examples/todos/src/main.rs
index 7faf742e..dfb73d96 100644
--- a/examples/todos/src/main.rs
+++ b/examples/todos/src/main.rs
@@ -4,7 +4,9 @@ use iced::widget::{
scrollable, text, text_input, Text,
};
use iced::window;
-use iced::{Center, Element, Fill, Font, Subscription, Task as Command};
+use iced::{
+ Center, Element, Fill, Font, Function, Subscription, Task as Command,
+};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
@@ -215,9 +217,8 @@ impl Todos {
.map(|(i, task)| {
(
task.id,
- task.view(i).map(move |message| {
- Message::TaskMessage(i, message)
- }),
+ task.view(i)
+ .map(Message::TaskMessage.with(i)),
)
}),
)
diff --git a/src/lib.rs b/src/lib.rs
index ce4a1e9d..441826d6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -505,9 +505,9 @@ pub use crate::core::gradient;
pub use crate::core::padding;
pub use crate::core::theme;
pub use crate::core::{
- never, with, Alignment, Animation, Background, Border, Color, ContentFit,
- Degrees, Gradient, Length, Padding, Pixels, Point, Radians, Rectangle,
- Rotation, Settings, Shadow, Size, Theme, Transformation, Vector,
+ never, Alignment, Animation, Background, Border, Color, ContentFit,
+ Degrees, Function, Gradient, Length, Padding, Pixels, Point, Radians,
+ Rectangle, Rotation, Settings, Shadow, Size, Theme, Transformation, Vector,
};
pub use crate::runtime::exit;
pub use iced_futures::Subscription;