summaryrefslogtreecommitdiffstats
path: root/web
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2021-09-01 19:21:49 +0700
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2021-09-02 13:29:34 +0700
commit76698ff2b5753e637b14533650c0d28e681be3c5 (patch)
tree6b3376df6ac84598b03f2885598b7908e993fe4a /web
parentb7b7741578257bbf6a8b873c360182e2c9b920ab (diff)
downloadiced-76698ff2b5753e637b14533650c0d28e681be3c5.tar.gz
iced-76698ff2b5753e637b14533650c0d28e681be3c5.tar.bz2
iced-76698ff2b5753e637b14533650c0d28e681be3c5.zip
Make `Command` implementations platform-specific
This allows us to introduce a platform-specific `Action` to both `iced_native` and `iced_web` and remove the `Clipboard` from `Application::update` to maintain purity. Additionally, this should let us implement further actions to let users query and modify the shell environment (e.g. window, clipboard, and more!)
Diffstat (limited to 'web')
-rw-r--r--web/src/clipboard.rs21
-rw-r--r--web/src/command.rs77
-rw-r--r--web/src/command/action.rs18
-rw-r--r--web/src/lib.rs49
4 files changed, 125 insertions, 40 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..606097de
--- /dev/null
+++ b/web/src/command.rs
@@ -0,0 +1,77 @@
+mod action;
+
+pub use action::Action;
+
+#[cfg(target_arch = "wasm32")]
+use std::future::Future;
+
+/// A set of asynchronous actions to be performed by some runtime.
+pub enum Command<T> {
+ None,
+ Single(Action<T>),
+ Batch(Vec<Action<T>>),
+}
+
+impl<T> Command<T> {
+ /// Creates an empty [`Command`].
+ ///
+ /// In other words, a [`Command`] that does nothing.
+ pub fn none() -> Self {
+ Self::None
+ }
+
+ /// 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))))
+ }
+
+ /// Applies a transformation to the result of a [`Command`].
+ #[cfg(target_arch = "wasm32")]
+ pub fn map<A>(mut self, f: impl Fn(T) -> A + 'static + Clone) -> Command<A>
+ where
+ T: 'static,
+ {
+ match self {
+ Self::None => Command::None,
+ Self::Single(action) => Command::Single(action.map(f)),
+ Self::Batch(batch) => Command::Batch(
+ batch
+ .into_iter()
+ .map(|action| action.map(f.clone()))
+ .collect(),
+ ),
+ }
+ }
+
+ /// 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 {
+ let mut batch = Vec::new();
+
+ for command in commands {
+ match command {
+ Self::None => {}
+ Self::Single(command) => batch.push(command),
+ Self::Batch(commands) => batch.extend(commands),
+ }
+ }
+
+ Self::Batch(batch)
+ }
+
+ pub fn actions(self) -> Vec<Action<T>> {
+ match self {
+ Self::None => Vec::new(),
+ Self::Single(action) => vec![action],
+ Self::Batch(batch) => batch,
+ }
+ }
+}
diff --git a/web/src/command/action.rs b/web/src/command/action.rs
new file mode 100644
index 00000000..cf384f07
--- /dev/null
+++ b/web/src/command/action.rs
@@ -0,0 +1,18 @@
+pub enum Action<T> {
+ Future(iced_futures::BoxFuture<T>),
+}
+
+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))),
+ }
+ }
+}
diff --git a/web/src/lib.rs b/web/src/lib.rs
index bb09bb0d..ec2bd178 100644
--- a/web/src/lib.rs
+++ b/web/src/lib.rs
@@ -50,8 +50,8 @@
//! [`wasm-pack`]: https://github.com/rustwasm/wasm-pack
//! [`wasm-bindgen`]: https://github.com/rustwasm/wasm-bindgen
//! [`tour` example]: https://github.com/hecrj/iced/tree/0.3/examples/tour
-#![deny(missing_docs)]
-#![deny(missing_debug_implementations)]
+//#![deny(missing_docs)]
+//#![deny(missing_debug_implementations)]
#![deny(unused_results)]
#![forbid(unsafe_code)]
#![forbid(rust_2018_idioms)]
@@ -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>,