diff options
author | 2021-09-13 11:49:06 +0700 | |
---|---|---|
committer | 2021-09-13 11:49:06 +0700 | |
commit | 93fec8d273ef8305e1c2456abe0c8ecd7a9d9407 (patch) | |
tree | c0c2445703133293b13657ab4f9c1c936e9cd688 /web/src | |
parent | 589f68df0f647d93f2b9dd7bf29cfacb0201351c (diff) | |
parent | 01b945b9814b9dc546e783a6dab66e4f7fe49786 (diff) | |
download | iced-93fec8d273ef8305e1c2456abe0c8ecd7a9d9407.tar.gz iced-93fec8d273ef8305e1c2456abe0c8ecd7a9d9407.tar.bz2 iced-93fec8d273ef8305e1c2456abe0c8ecd7a9d9407.zip |
Merge pull request #1019 from hecrj/command-actions
Platform-specific `Command` implementations
Diffstat (limited to 'web/src')
-rw-r--r-- | web/src/clipboard.rs | 21 | ||||
-rw-r--r-- | web/src/command.rs | 72 | ||||
-rw-r--r-- | web/src/command/action.rs | 28 | ||||
-rw-r--r-- | web/src/lib.rs | 45 |
4 files changed, 128 insertions, 38 deletions
diff --git a/web/src/clipboard.rs b/web/src/clipboard.rs deleted file mode 100644 index 167a1e53..00000000 --- a/web/src/clipboard.rs +++ /dev/null @@ -1,21 +0,0 @@ -/// A buffer for short-term storage and transfer within and between -/// applications. -#[derive(Debug, Clone, Copy)] -pub struct Clipboard; - -impl Clipboard { - /// Creates a new [`Clipboard`]. - pub fn new() -> Self { - Self - } - - /// Reads the current content of the [`Clipboard`] as text. - pub fn read(&self) -> Option<String> { - unimplemented! {} - } - - /// Writes the given text contents to the [`Clipboard`]. - pub fn write(&mut self, _contents: String) { - unimplemented! {} - } -} diff --git a/web/src/command.rs b/web/src/command.rs new file mode 100644 index 00000000..33e49e70 --- /dev/null +++ b/web/src/command.rs @@ -0,0 +1,72 @@ +mod action; + +pub use action::Action; + +use std::fmt; + +#[cfg(target_arch = "wasm32")] +use std::future::Future; + +/// A set of asynchronous actions to be performed by some runtime. +pub struct Command<T>(iced_futures::Command<Action<T>>); + +impl<T> Command<T> { + /// Creates an empty [`Command`]. + /// + /// In other words, a [`Command`] that does nothing. + pub const fn none() -> Self { + Self(iced_futures::Command::none()) + } + + /// Creates a [`Command`] that performs a single [`Action`]. + pub const fn single(action: Action<T>) -> Self { + Self(iced_futures::Command::single(action)) + } + + /// Creates a [`Command`] that performs the action of the given future. + #[cfg(target_arch = "wasm32")] + pub fn perform<A>( + future: impl Future<Output = T> + 'static, + f: impl Fn(T) -> A + 'static + Send, + ) -> Command<A> { + use iced_futures::futures::FutureExt; + + Command::single(Action::Future(Box::pin(future.map(f)))) + } + + /// Creates a [`Command`] that performs the actions of all the given + /// commands. + /// + /// Once this command is run, all the commands will be executed at once. + pub fn batch(commands: impl IntoIterator<Item = Command<T>>) -> Self { + Self(iced_futures::Command::batch( + commands.into_iter().map(|Command(command)| command), + )) + } + + /// Applies a transformation to the result of a [`Command`]. + #[cfg(target_arch = "wasm32")] + pub fn map<A>(self, f: impl Fn(T) -> A + 'static + Clone) -> Command<A> + where + T: 'static, + { + let Command(command) = self; + + Command(command.map(move |action| action.map(f.clone()))) + } + + /// Returns all of the actions of the [`Command`]. + pub fn actions(self) -> Vec<Action<T>> { + let Command(command) = self; + + command.actions() + } +} + +impl<T> fmt::Debug for Command<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Command(command) = self; + + command.fmt(f) + } +} diff --git a/web/src/command/action.rs b/web/src/command/action.rs new file mode 100644 index 00000000..c0223e50 --- /dev/null +++ b/web/src/command/action.rs @@ -0,0 +1,28 @@ +pub enum Action<T> { + Future(iced_futures::BoxFuture<T>), +} + +use std::fmt; + +impl<T> Action<T> { + /// Applies a transformation to the result of a [`Command`]. + #[cfg(target_arch = "wasm32")] + pub fn map<A>(self, f: impl Fn(T) -> A + 'static) -> Action<A> + where + T: 'static, + { + use iced_futures::futures::FutureExt; + + match self { + Self::Future(future) => Action::Future(Box::pin(future.map(f))), + } + } +} + +impl<T> fmt::Debug for Action<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Future(_) => write!(f, "Action::Future"), + } + } +} diff --git a/web/src/lib.rs b/web/src/lib.rs index bb09bb0d..5bbd2ee6 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -59,7 +59,7 @@ use dodrio::bumpalo; use std::{cell::RefCell, rc::Rc}; mod bus; -mod clipboard; +mod command; mod element; mod hasher; @@ -68,7 +68,7 @@ pub mod subscription; pub mod widget; pub use bus::Bus; -pub use clipboard::Clipboard; +pub use command::Command; pub use css::Css; pub use dodrio; pub use element::Element; @@ -77,7 +77,7 @@ pub use iced_core::{ keyboard, menu, mouse, Align, Background, Color, Font, HorizontalAlignment, Length, Menu, Padding, Point, Rectangle, Size, Vector, VerticalAlignment, }; -pub use iced_futures::{executor, futures, Command}; +pub use iced_futures::{executor, futures}; pub use subscription::Subscription; #[doc(no_inline)] @@ -128,11 +128,7 @@ pub trait Application { /// this method. /// /// Any [`Command`] returned will be executed immediately in the background. - fn update( - &mut self, - message: Self::Message, - clipboard: &mut Clipboard, - ) -> Command<Self::Message>; + fn update(&mut self, message: Self::Message) -> Command<Self::Message>; /// Returns the widgets to display in the [`Application`]. /// @@ -162,8 +158,6 @@ pub trait Application { let document = window.document().unwrap(); let body = document.body().unwrap(); - let mut clipboard = Clipboard::new(); - let (sender, receiver) = iced_futures::futures::channel::mpsc::unbounded(); @@ -177,7 +171,7 @@ pub trait Application { let mut title = app.title(); document.set_title(&title); - runtime.spawn(command); + run_command(command, &mut runtime); let application = Rc::new(RefCell::new(app)); @@ -190,8 +184,7 @@ pub trait Application { let event_loop = receiver.for_each(move |message| { let (command, subscription) = runtime.enter(|| { - let command = - application.borrow_mut().update(message, &mut clipboard); + let command = application.borrow_mut().update(message); let subscription = application.borrow().subscription(); (command, subscription) @@ -199,7 +192,7 @@ pub trait Application { let new_title = application.borrow().title(); - runtime.spawn(command); + run_command(command, &mut runtime); runtime.track(subscription); if title != new_title { @@ -350,8 +343,7 @@ pub trait Embedded { ); let (app, command) = runtime.enter(|| Self::new(flags)); - - runtime.spawn(command); + run_command(command, &mut runtime); let application = Rc::new(RefCell::new(app)); @@ -370,7 +362,7 @@ pub trait Embedded { (command, subscription) }); - runtime.spawn(command); + run_command(command, &mut runtime); runtime.track(subscription); vdom.weak().schedule_render(); @@ -382,6 +374,25 @@ pub trait Embedded { } } +fn run_command<Message: 'static + Send, E: Executor>( + command: Command<Message>, + runtime: &mut iced_futures::Runtime< + Hasher, + (), + E, + iced_futures::futures::channel::mpsc::UnboundedSender<Message>, + Message, + >, +) { + for action in command.actions() { + match action { + command::Action::Future(future) => { + runtime.spawn(future); + } + } + } +} + struct EmbeddedInstance<A: Embedded> { application: Rc<RefCell<A>>, bus: Bus<A::Message>, |