diff options
Diffstat (limited to 'futures')
-rw-r--r-- | futures/Cargo.toml | 5 | ||||
-rw-r--r-- | futures/src/command.rs | 52 | ||||
-rw-r--r-- | futures/src/lib.rs | 7 | ||||
-rw-r--r-- | futures/src/time.rs | 70 |
4 files changed, 132 insertions, 2 deletions
diff --git a/futures/Cargo.toml b/futures/Cargo.toml index e0815d9d..275d0391 100644 --- a/futures/Cargo.toml +++ b/futures/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "iced_futures" -version = "0.1.1" +version = "0.1.2" authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] edition = "2018" description = "Commands, subscriptions, and runtimes for Iced" @@ -22,11 +22,12 @@ version = "0.3" [target.'cfg(not(target_arch = "wasm32"))'.dependencies.tokio] version = "0.2" optional = true -features = ["rt-core", "rt-threaded"] +features = ["rt-core", "rt-threaded", "time", "stream"] [target.'cfg(not(target_arch = "wasm32"))'.dependencies.async-std] version = "1.0" optional = true +features = ["unstable"] [target.'cfg(target_arch = "wasm32")'.dependencies] wasm-bindgen-futures = "0.4" diff --git a/futures/src/command.rs b/futures/src/command.rs index d4f99b82..063e9b68 100644 --- a/futures/src/command.rs +++ b/futures/src/command.rs @@ -27,6 +27,7 @@ impl<T> Command<T> { /// Creates a [`Command`] that performs the action of the given future. /// /// [`Command`]: struct.Command.html + #[cfg(not(target_arch = "wasm32"))] pub fn perform<A>( future: impl Future<Output = T> + 'static + Send, f: impl Fn(T) -> A + 'static + Send, @@ -36,9 +37,23 @@ impl<T> Command<T> { } } + /// Creates a [`Command`] that performs the action of the given future. + /// + /// [`Command`]: struct.Command.html + #[cfg(target_arch = "wasm32")] + pub fn perform<A>( + future: impl Future<Output = T> + 'static, + f: impl Fn(T) -> A + 'static + Send, + ) -> Command<A> { + Command { + futures: vec![Box::pin(future.map(f))], + } + } + /// Applies a transformation to the result of a [`Command`]. /// /// [`Command`]: struct.Command.html + #[cfg(not(target_arch = "wasm32"))] pub fn map<A>( mut self, f: impl Fn(T) -> A + 'static + Send + Sync, @@ -62,6 +77,30 @@ impl<T> Command<T> { } } + /// Applies a transformation to the result of a [`Command`]. + /// + /// [`Command`]: struct.Command.html + #[cfg(target_arch = "wasm32")] + pub fn map<A>(mut self, f: impl Fn(T) -> A + 'static) -> Command<A> + where + T: 'static, + { + let f = std::rc::Rc::new(f); + + Command { + futures: self + .futures + .drain(..) + .map(|future| { + let f = f.clone(); + + Box::pin(future.map(move |result| f(result))) + as BoxFuture<A> + }) + .collect(), + } + } + /// Creates a [`Command`] that performs the actions of all the given /// commands. /// @@ -85,6 +124,7 @@ impl<T> Command<T> { } } +#[cfg(not(target_arch = "wasm32"))] impl<T, A> From<A> for Command<T> where A: Future<Output = T> + 'static + Send, @@ -96,6 +136,18 @@ where } } +#[cfg(target_arch = "wasm32")] +impl<T, A> From<A> for Command<T> +where + A: Future<Output = T> + 'static, +{ + fn from(future: A) -> Self { + Self { + futures: vec![future.boxed_local()], + } + } +} + impl<T> std::fmt::Debug for Command<T> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Command").finish() diff --git a/futures/src/lib.rs b/futures/src/lib.rs index 966a9cdc..46fc59fc 100644 --- a/futures/src/lib.rs +++ b/futures/src/lib.rs @@ -14,6 +14,13 @@ mod runtime; pub mod executor; pub mod subscription; +#[cfg(all( + any(feature = "tokio", feature = "async-std"), + not(target_arch = "wasm32") +))] +#[cfg_attr(docsrs, doc(cfg(any(feature = "tokio", feature = "async-std"))))] +pub mod time; + pub use command::Command; pub use executor::Executor; pub use runtime::Runtime; diff --git a/futures/src/time.rs b/futures/src/time.rs new file mode 100644 index 00000000..e87b4a83 --- /dev/null +++ b/futures/src/time.rs @@ -0,0 +1,70 @@ +//! Listen and react to time. +use crate::subscription::{self, Subscription}; + +/// Returns a [`Subscription`] that produces messages at a set interval. +/// +/// The first message is produced after a `duration`, and then continues to +/// produce more messages every `duration` after that. +/// +/// [`Subscription`]: ../subscription/struct.Subscription.html +pub fn every<H: std::hash::Hasher, E>( + duration: std::time::Duration, +) -> Subscription<H, E, std::time::Instant> { + Subscription::from_recipe(Every(duration)) +} + +struct Every(std::time::Duration); + +#[cfg(feature = "async-std")] +impl<H, E> subscription::Recipe<H, E> for Every +where + H: std::hash::Hasher, +{ + type Output = std::time::Instant; + + fn hash(&self, state: &mut H) { + use std::hash::Hash; + + std::any::TypeId::of::<Self>().hash(state); + self.0.hash(state); + } + + fn stream( + self: Box<Self>, + _input: futures::stream::BoxStream<'static, E>, + ) -> futures::stream::BoxStream<'static, Self::Output> { + use futures::stream::StreamExt; + + async_std::stream::interval(self.0) + .map(|_| std::time::Instant::now()) + .boxed() + } +} + +#[cfg(all(feature = "tokio", not(feature = "async-std")))] +impl<H, E> subscription::Recipe<H, E> for Every +where + H: std::hash::Hasher, +{ + type Output = std::time::Instant; + + fn hash(&self, state: &mut H) { + use std::hash::Hash; + + std::any::TypeId::of::<Self>().hash(state); + self.0.hash(state); + } + + fn stream( + self: Box<Self>, + _input: futures::stream::BoxStream<'static, E>, + ) -> futures::stream::BoxStream<'static, Self::Output> { + use futures::stream::StreamExt; + + let start = tokio::time::Instant::now() + self.0; + + tokio::time::interval_at(start, self.0) + .map(|_| std::time::Instant::now()) + .boxed() + } +} |