Replace with function with Function trait
This commit is contained in:
parent
080db34849
commit
eab723866e
7 changed files with 75 additions and 79 deletions
107
core/src/lib.rs
107
core/src/lib.rs
|
|
@ -94,62 +94,59 @@ pub fn never<T>(never: std::convert::Infallible) -> T {
|
||||||
match never {}
|
match never {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Applies the given prefix value to the provided closure and returns
|
/// A trait extension for binary functions (`Fn(A, B) -> O`).
|
||||||
/// a new closure that takes the other argument.
|
|
||||||
///
|
///
|
||||||
/// This lets you partially "apply" a function—equivalent to currying,
|
/// It enables you to use a bunch of nifty functional programming paradigms
|
||||||
/// but it only works with binary functions. If you want to apply an
|
/// that work well with iced.
|
||||||
/// arbitrary number of arguments, use the [`with!`] macro instead.
|
pub trait Function<A, B, O> {
|
||||||
///
|
/// Applies the given first argument to a binary function and returns
|
||||||
/// # When is this useful?
|
/// a new function that takes the other argument.
|
||||||
/// Sometimes you will want to identify the source or target
|
///
|
||||||
/// of some message in your user interface. This can be achieved through
|
/// This lets you partially "apply" a function—equivalent to currying,
|
||||||
/// normal means by defining a closure and moving the identifier
|
/// but it only works with binary functions. If you want to apply an
|
||||||
/// inside:
|
/// arbitrary number of arguments, create a little struct for them.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// # When is this useful?
|
||||||
/// # let element: Option<()> = Some(());
|
/// Sometimes you will want to identify the source or target
|
||||||
/// # enum Message { ButtonPressed(u32, ()) }
|
/// of some message in your user interface. This can be achieved through
|
||||||
/// let id = 123;
|
/// normal means by defining a closure and moving the identifier
|
||||||
///
|
/// inside:
|
||||||
/// # let _ = {
|
///
|
||||||
/// element.map(move |result| Message::ButtonPressed(id, result))
|
/// ```rust
|
||||||
/// # };
|
/// # let element: Option<()> = Some(());
|
||||||
/// ```
|
/// # enum Message { ButtonPressed(u32, ()) }
|
||||||
///
|
/// let id = 123;
|
||||||
/// That's quite a mouthful. [`with()`] lets you write:
|
///
|
||||||
///
|
/// # let _ = {
|
||||||
/// ```rust
|
/// element.map(move |result| Message::ButtonPressed(id, result))
|
||||||
/// # use iced_core::with;
|
/// # };
|
||||||
/// # let element: Option<()> = Some(());
|
/// ```
|
||||||
/// # enum Message { ButtonPressed(u32, ()) }
|
///
|
||||||
/// let id = 123;
|
/// That's quite a mouthful. [`with`] lets you write:
|
||||||
///
|
///
|
||||||
/// # let _ = {
|
/// ```rust
|
||||||
/// element.map(with(Message::ButtonPressed, id))
|
/// # use iced_core::Function;
|
||||||
/// # };
|
/// # let element: Option<()> = Some(());
|
||||||
/// ```
|
/// # enum Message { ButtonPressed(u32, ()) }
|
||||||
///
|
/// let id = 123;
|
||||||
/// Effectively creating the same closure that partially applies
|
///
|
||||||
/// the `id` to the message—but much more concise!
|
/// # let _ = {
|
||||||
pub fn with<T, R, O>(
|
/// element.map(Message::ButtonPressed.with(id))
|
||||||
mut f: impl FnMut(T, R) -> O,
|
/// # };
|
||||||
prefix: T,
|
/// ```
|
||||||
) -> impl FnMut(R) -> O
|
///
|
||||||
where
|
/// Effectively creating the same closure that partially applies
|
||||||
T: Copy,
|
/// the `id` to the message—but much more concise!
|
||||||
{
|
fn with(self, prefix: A) -> impl Fn(B) -> O;
|
||||||
move |result| f(prefix, result)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Applies the given prefix values to the provided closure in the first
|
impl<F, A, B, O> Function<A, B, O> for F
|
||||||
/// argument and returns a new closure that takes its last argument.
|
where
|
||||||
///
|
F: Fn(A, B) -> O,
|
||||||
/// This is a variadic version of [`with()`] which works with any number of
|
Self: Sized,
|
||||||
/// arguments.
|
A: Copy,
|
||||||
#[macro_export]
|
{
|
||||||
macro_rules! with {
|
fn with(self, prefix: A) -> impl Fn(B) -> O {
|
||||||
($f:expr, $($x:expr),+ $(,)?) => {
|
move |result| self(prefix, result)
|
||||||
move |result| $f($($x),+, result)
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use download::download;
|
||||||
|
|
||||||
use iced::task;
|
use iced::task;
|
||||||
use iced::widget::{button, center, column, progress_bar, text, Column};
|
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 {
|
pub fn main() -> iced::Result {
|
||||||
iced::application(
|
iced::application(
|
||||||
|
|
@ -52,7 +52,7 @@ impl Example {
|
||||||
|
|
||||||
let task = download.start();
|
let task = download.start();
|
||||||
|
|
||||||
task.map(with(Message::DownloadUpdated, index))
|
task.map(Message::DownloadUpdated.with(index))
|
||||||
}
|
}
|
||||||
Message::DownloadUpdated(id, update) => {
|
Message::DownloadUpdated(id, update) => {
|
||||||
if let Some(download) =
|
if let Some(download) =
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ use iced::widget::{
|
||||||
};
|
};
|
||||||
use iced::window;
|
use iced::window;
|
||||||
use iced::{
|
use iced::{
|
||||||
color, with, Animation, ContentFit, Element, Fill, Subscription, Task,
|
color, Animation, ContentFit, Element, Fill, Function, Subscription, Task,
|
||||||
Theme,
|
Theme,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -100,8 +100,8 @@ impl Gallery {
|
||||||
width: Preview::WIDTH,
|
width: Preview::WIDTH,
|
||||||
height: Preview::HEIGHT,
|
height: Preview::HEIGHT,
|
||||||
}),
|
}),
|
||||||
with(Message::BlurhashDecoded, id),
|
Message::BlurhashDecoded.with(id),
|
||||||
with(Message::ThumbnailDownloaded, id),
|
Message::ThumbnailDownloaded.with(id),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Message::ImageDownloaded(Ok(rgba)) => {
|
Message::ImageDownloaded(Ok(rgba)) => {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use iced::time::{self, milliseconds};
|
||||||
use iced::widget::{
|
use iced::widget::{
|
||||||
button, checkbox, column, container, pick_list, row, slider, text,
|
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 {
|
pub fn main() -> iced::Result {
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
|
|
@ -37,7 +37,7 @@ struct GameOfLife {
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
enum Message {
|
enum Message {
|
||||||
Grid(grid::Message, usize),
|
Grid(usize, grid::Message),
|
||||||
Tick,
|
Tick,
|
||||||
TogglePlayback,
|
TogglePlayback,
|
||||||
ToggleGrid(bool),
|
ToggleGrid(bool),
|
||||||
|
|
@ -61,7 +61,7 @@ impl GameOfLife {
|
||||||
|
|
||||||
fn update(&mut self, message: Message) -> Task<Message> {
|
fn update(&mut self, message: Message) -> Task<Message> {
|
||||||
match message {
|
match message {
|
||||||
Message::Grid(message, version) => {
|
Message::Grid(version, message) => {
|
||||||
if version == self.version {
|
if version == self.version {
|
||||||
self.grid.update(message);
|
self.grid.update(message);
|
||||||
}
|
}
|
||||||
|
|
@ -78,9 +78,7 @@ impl GameOfLife {
|
||||||
|
|
||||||
let version = self.version;
|
let version = self.version;
|
||||||
|
|
||||||
return Task::perform(task, move |message| {
|
return Task::perform(task, Message::Grid.with(version));
|
||||||
Message::Grid(message, version)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::TogglePlayback => {
|
Message::TogglePlayback => {
|
||||||
|
|
@ -129,9 +127,7 @@ impl GameOfLife {
|
||||||
);
|
);
|
||||||
|
|
||||||
let content = column![
|
let content = column![
|
||||||
self.grid
|
self.grid.view().map(Message::Grid.with(version)),
|
||||||
.view()
|
|
||||||
.map(move |message| Message::Grid(message, version)),
|
|
||||||
controls,
|
controls,
|
||||||
]
|
]
|
||||||
.height(Fill);
|
.height(Fill);
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@ use iced::widget::{
|
||||||
text_input,
|
text_input,
|
||||||
};
|
};
|
||||||
use iced::window;
|
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;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
|
@ -169,7 +171,7 @@ impl Window {
|
||||||
let scale_input = column![
|
let scale_input = column![
|
||||||
text("Window scale factor:"),
|
text("Window scale factor:"),
|
||||||
text_input("Window Scale", &self.scale_input)
|
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(
|
.on_submit(Message::ScaleChanged(
|
||||||
id,
|
id,
|
||||||
self.scale_input.to_string()
|
self.scale_input.to_string()
|
||||||
|
|
@ -179,7 +181,7 @@ impl Window {
|
||||||
let title_input = column![
|
let title_input = column![
|
||||||
text("Window title:"),
|
text("Window title:"),
|
||||||
text_input("Window Title", &self.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}"))
|
.id(format!("input-{id}"))
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,9 @@ use iced::widget::{
|
||||||
scrollable, text, text_input, Text,
|
scrollable, text, text_input, Text,
|
||||||
};
|
};
|
||||||
use iced::window;
|
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 serde::{Deserialize, Serialize};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
@ -215,9 +217,8 @@ impl Todos {
|
||||||
.map(|(i, task)| {
|
.map(|(i, task)| {
|
||||||
(
|
(
|
||||||
task.id,
|
task.id,
|
||||||
task.view(i).map(move |message| {
|
task.view(i)
|
||||||
Message::TaskMessage(i, message)
|
.map(Message::TaskMessage.with(i)),
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -505,9 +505,9 @@ pub use crate::core::gradient;
|
||||||
pub use crate::core::padding;
|
pub use crate::core::padding;
|
||||||
pub use crate::core::theme;
|
pub use crate::core::theme;
|
||||||
pub use crate::core::{
|
pub use crate::core::{
|
||||||
never, with, Alignment, Animation, Background, Border, Color, ContentFit,
|
never, Alignment, Animation, Background, Border, Color, ContentFit,
|
||||||
Degrees, Gradient, Length, Padding, Pixels, Point, Radians, Rectangle,
|
Degrees, Function, Gradient, Length, Padding, Pixels, Point, Radians,
|
||||||
Rotation, Settings, Shadow, Size, Theme, Transformation, Vector,
|
Rectangle, Rotation, Settings, Shadow, Size, Theme, Transformation, Vector,
|
||||||
};
|
};
|
||||||
pub use crate::runtime::exit;
|
pub use crate::runtime::exit;
|
||||||
pub use iced_futures::Subscription;
|
pub use iced_futures::Subscription;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue