diff options
| -rw-r--r-- | futures/src/command.rs | 107 | ||||
| -rw-r--r-- | futures/src/command/native.rs | 100 | ||||
| -rw-r--r-- | futures/src/command/web.rs | 101 | ||||
| -rw-r--r-- | futures/src/lib.rs | 28 | ||||
| -rw-r--r-- | futures/src/subscription.rs | 34 | ||||
| -rw-r--r-- | futures/src/subscription/tracker.rs | 10 | ||||
| -rw-r--r-- | native/src/subscription/events.rs | 4 | 
7 files changed, 149 insertions, 235 deletions
diff --git a/futures/src/command.rs b/futures/src/command.rs index 26f58fde..535ae4f7 100644 --- a/futures/src/command.rs +++ b/futures/src/command.rs @@ -1,11 +1,102 @@ -#[cfg(not(target_arch = "wasm32"))] -mod native; +use crate::BoxFuture; +use futures::future::{Future, FutureExt}; -#[cfg(not(target_arch = "wasm32"))] -pub use native::Command; +/// A collection of async operations. +/// +/// You should be able to turn a future easily into a [`Command`], either by +/// using the `From` trait or [`Command::perform`]. +/// +/// [`Command`]: struct.Command.html +pub struct Command<T> { +    futures: Vec<BoxFuture<T>>, +} -#[cfg(target_arch = "wasm32")] -mod web; +impl<T> Command<T> { +    /// Creates an empty [`Command`]. +    /// +    /// In other words, a [`Command`] that does nothing. +    /// +    /// [`Command`]: struct.Command.html +    pub fn none() -> Self { +        Self { +            futures: Vec::new(), +        } +    } -#[cfg(target_arch = "wasm32")] -pub use web::Command; +    /// Creates a [`Command`] that performs the action of the given future. +    /// +    /// [`Command`]: struct.Command.html +    pub fn perform<A>( +        future: impl Future<Output = T> + 'static + Send, +        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 +    pub fn map<A>( +        mut self, +        f: impl Fn(T) -> A + 'static + Send + Sync, +    ) -> Command<A> +    where +        T: 'static, +    { +        let f = std::sync::Arc::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. +    /// +    /// Once this command is run, all the commands will be executed at once. +    /// +    /// [`Command`]: struct.Command.html +    pub fn batch(commands: impl IntoIterator<Item = Command<T>>) -> Self { +        Self { +            futures: commands +                .into_iter() +                .flat_map(|command| command.futures) +                .collect(), +        } +    } + +    /// Converts a [`Command`] into its underlying list of futures. +    /// +    /// [`Command`]: struct.Command.html +    pub fn futures(self) -> Vec<BoxFuture<T>> { +        self.futures +    } +} + +impl<T, A> From<A> for Command<T> +where +    A: Future<Output = T> + 'static + Send, +{ +    fn from(future: A) -> Self { +        Self { +            futures: vec![future.boxed()], +        } +    } +} + +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/command/native.rs b/futures/src/command/native.rs deleted file mode 100644 index 38cb4e06..00000000 --- a/futures/src/command/native.rs +++ /dev/null @@ -1,100 +0,0 @@ -use futures::future::{BoxFuture, Future, FutureExt}; - -/// A collection of async operations. -/// -/// You should be able to turn a future easily into a [`Command`], either by -/// using the `From` trait or [`Command::perform`]. -/// -/// [`Command`]: struct.Command.html -pub struct Command<T> { -    futures: Vec<BoxFuture<'static, T>>, -} - -impl<T> Command<T> { -    /// Creates an empty [`Command`]. -    /// -    /// In other words, a [`Command`] that does nothing. -    /// -    /// [`Command`]: struct.Command.html -    pub fn none() -> Self { -        Self { -            futures: Vec::new(), -        } -    } - -    /// Creates a [`Command`] that performs the action of the given future. -    /// -    /// [`Command`]: struct.Command.html -    pub fn perform<A>( -        future: impl Future<Output = T> + 'static + Send, -        f: impl Fn(T) -> A + 'static + Send, -    ) -> Command<A> { -        Command { -            futures: vec![future.map(f).boxed()], -        } -    } - -    /// Applies a transformation to the result of a [`Command`]. -    /// -    /// [`Command`]: struct.Command.html -    pub fn map<A>( -        mut self, -        f: impl Fn(T) -> A + 'static + Send + Sync, -    ) -> Command<A> -    where -        T: 'static, -    { -        let f = std::sync::Arc::new(f); - -        Command { -            futures: self -                .futures -                .drain(..) -                .map(|future| { -                    let f = f.clone(); - -                    future.map(move |result| f(result)).boxed() -                }) -                .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. -    /// -    /// [`Command`]: struct.Command.html -    pub fn batch(commands: impl IntoIterator<Item = Command<T>>) -> Self { -        Self { -            futures: commands -                .into_iter() -                .flat_map(|command| command.futures) -                .collect(), -        } -    } - -    /// Converts a [`Command`] into its underlying list of futures. -    /// -    /// [`Command`]: struct.Command.html -    pub fn futures(self) -> Vec<BoxFuture<'static, T>> { -        self.futures -    } -} - -impl<T, A> From<A> for Command<T> -where -    A: Future<Output = T> + 'static + Send, -{ -    fn from(future: A) -> Self { -        Self { -            futures: vec![future.boxed()], -        } -    } -} - -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/command/web.rs b/futures/src/command/web.rs deleted file mode 100644 index 11b46b90..00000000 --- a/futures/src/command/web.rs +++ /dev/null @@ -1,101 +0,0 @@ -use futures::future::{Future, FutureExt}; -use std::pin::Pin; - -/// A collection of async operations. -/// -/// You should be able to turn a future easily into a [`Command`], either by -/// using the `From` trait or [`Command::perform`]. -/// -/// [`Command`]: struct.Command.html -pub struct Command<T> { -    futures: Vec<Pin<Box<dyn Future<Output = T> + 'static>>>, -} - -impl<T> Command<T> { -    /// Creates an empty [`Command`]. -    /// -    /// In other words, a [`Command`] that does nothing. -    /// -    /// [`Command`]: struct.Command.html -    pub fn none() -> Self { -        Self { -            futures: Vec::new(), -        } -    } - -    /// Creates a [`Command`] that performs the action of the given future. -    /// -    /// [`Command`]: struct.Command.html -    pub fn perform<A>( -        future: impl Future<Output = T> + 'static, -        f: impl Fn(T) -> A + 'static, -    ) -> Command<A> { -        Command { -            futures: vec![future.map(f).boxed_local()], -        } -    } - -    /// Applies a transformation to the result of a [`Command`]. -    /// -    /// [`Command`]: struct.Command.html -    pub fn map<A>( -        mut self, -        f: impl Fn(T) -> A + 'static + Send + Sync + Unpin, -    ) -> Command<A> -    where -        T: 'static, -    { -        let f = std::sync::Arc::new(f); - -        Command { -            futures: self -                .futures -                .drain(..) -                .map(|future| { -                    let f = f.clone(); - -                    future.map(move |result| f(result)).boxed_local() -                }) -                .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. -    /// -    /// [`Command`]: struct.Command.html -    pub fn batch(commands: impl IntoIterator<Item = Command<T>>) -> Self { -        Self { -            futures: commands -                .into_iter() -                .flat_map(|command| command.futures) -                .collect(), -        } -    } - -    /// Converts a [`Command`] into its underlying list of futures. -    /// -    /// [`Command`]: struct.Command.html -    pub fn futures(self) -> Vec<Pin<Box<dyn Future<Output = T> + 'static>>> { -        self.futures -    } -} - -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 c25c0853..79178931 100644 --- a/futures/src/lib.rs +++ b/futures/src/lib.rs @@ -16,3 +16,31 @@ pub use command::Command;  pub use executor::Executor;  pub use runtime::Runtime;  pub use subscription::Subscription; + +/// A boxed static future. +/// +/// - On native platforms, it needs a `Send` requirement. +/// - On the Web platform, it does not need a `Send` requirement. +#[cfg(not(target_arch = "wasm32"))] +pub type BoxFuture<T> = futures::future::BoxFuture<'static, T>; + +/// A boxed static future. +/// +/// - On native platforms, it needs a `Send` requirement. +/// - On the Web platform, it does not need a `Send` requirement. +#[cfg(target_arch = "wasm32")] +pub type BoxFuture<T> = futures::future::LocalBoxFuture<'static, T>; + +/// A boxed static stream. +/// +/// - On native platforms, it needs a `Send` requirement. +/// - On the Web platform, it does not need a `Send` requirement. +#[cfg(not(target_arch = "wasm32"))] +pub type BoxStream<T> = futures::stream::BoxStream<'static, T>; + +/// A boxed static stream. +/// +/// - On native platforms, it needs a `Send` requirement. +/// - On the Web platform, it does not need a `Send` requirement. +#[cfg(target_arch = "wasm32")] +pub type BoxStream<T> = futures::stream::LocalBoxStream<'static, T>; diff --git a/futures/src/subscription.rs b/futures/src/subscription.rs index 8eccb7be..ab333a20 100644 --- a/futures/src/subscription.rs +++ b/futures/src/subscription.rs @@ -3,7 +3,7 @@ mod tracker;  pub use tracker::Tracker; -use futures::stream::BoxStream; +use crate::BoxStream;  /// A request to listen to external events.  /// @@ -168,8 +168,8 @@ pub trait Recipe<Hasher: std::hash::Hasher, Event> {      /// [`Recipe`]: trait.Recipe.html      fn stream(          self: Box<Self>, -        input: BoxStream<'static, Event>, -    ) -> BoxStream<'static, Self::Output>; +        input: BoxStream<Event>, +    ) -> BoxStream<Self::Output>;  }  struct Map<Hasher, Event, A, B> { @@ -201,18 +201,16 @@ where          self.recipe.hash(state);      } -    fn stream( -        self: Box<Self>, -        input: BoxStream<'static, E>, -    ) -> futures::stream::BoxStream<'static, Self::Output> { +    fn stream(self: Box<Self>, input: BoxStream<E>) -> BoxStream<Self::Output> {          use futures::StreamExt;          let mapper = self.mapper; -        self.recipe -            .stream(input) -            .map(move |element| mapper(element)) -            .boxed() +        Box::pin( +            self.recipe +                .stream(input) +                .map(move |element| mapper(element)), +        )      }  } @@ -243,17 +241,15 @@ where          self.recipe.hash(state);      } -    fn stream( -        self: Box<Self>, -        input: BoxStream<'static, E>, -    ) -> futures::stream::BoxStream<'static, Self::Output> { +    fn stream(self: Box<Self>, input: BoxStream<E>) -> BoxStream<Self::Output> {          use futures::StreamExt;          let value = self.value; -        self.recipe -            .stream(input) -            .map(move |element| (value.clone(), element)) -            .boxed() +        Box::pin( +            self.recipe +                .stream(input) +                .map(move |element| (value.clone(), element)), +        )      }  } diff --git a/futures/src/subscription/tracker.rs b/futures/src/subscription/tracker.rs index cfa36170..efb464b5 100644 --- a/futures/src/subscription/tracker.rs +++ b/futures/src/subscription/tracker.rs @@ -1,6 +1,6 @@ -use crate::Subscription; +use crate::{BoxFuture, Subscription}; -use futures::{channel::mpsc, future::BoxFuture, sink::Sink}; +use futures::{channel::mpsc, sink::Sink};  use std::{collections::HashMap, marker::PhantomData};  /// A registry of subscription streams. @@ -59,7 +59,7 @@ where          &mut self,          subscription: Subscription<Hasher, Event, Message>,          receiver: Receiver, -    ) -> Vec<BoxFuture<'static, ()>> +    ) -> Vec<BoxFuture<()>>      where          Message: 'static + Send,          Receiver: 'static @@ -70,7 +70,7 @@ where      {          use futures::{future::FutureExt, stream::StreamExt}; -        let mut futures = Vec::new(); +        let mut futures: Vec<BoxFuture<()>> = Vec::new();          let recipes = subscription.recipes();          let mut alive = std::collections::HashSet::new(); @@ -115,7 +115,7 @@ where                  },              ); -            futures.push(future.boxed()); +            futures.push(Box::pin(future));          }          self.subscriptions.retain(|id, _| alive.contains(&id)); diff --git a/native/src/subscription/events.rs b/native/src/subscription/events.rs index 7d33166e..ceae467d 100644 --- a/native/src/subscription/events.rs +++ b/native/src/subscription/events.rs @@ -2,7 +2,7 @@ use crate::{      subscription::{EventStream, Recipe},      Event, Hasher,  }; -use iced_futures::futures::stream::BoxStream; +use iced_futures::BoxStream;  pub struct Events; @@ -18,7 +18,7 @@ impl Recipe<Hasher, Event> for Events {      fn stream(          self: Box<Self>,          event_stream: EventStream, -    ) -> BoxStream<'static, Self::Output> { +    ) -> BoxStream<Self::Output> {          event_stream      }  }  | 
