Merge pull request #234 from hecrj/improvement/subscription-send-requirement
Improve compatibility of `iced_futures`
This commit is contained in:
commit
9ef1801ed6
@ -1,11 +1,102 @@
|
|||||||
#[cfg(not(target_arch = "wasm32"))]
|
use crate::BoxFuture;
|
||||||
mod native;
|
use futures::future::{Future, FutureExt};
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
/// A collection of async operations.
|
||||||
pub use native::Command;
|
///
|
||||||
|
/// 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")]
|
impl<T> Command<T> {
|
||||||
mod web;
|
/// 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")]
|
/// Creates a [`Command`] that performs the action of the given future.
|
||||||
pub use web::Command;
|
///
|
||||||
|
/// [`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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
@ -16,3 +16,31 @@ pub use command::Command;
|
|||||||
pub use executor::Executor;
|
pub use executor::Executor;
|
||||||
pub use runtime::Runtime;
|
pub use runtime::Runtime;
|
||||||
pub use subscription::Subscription;
|
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>;
|
||||||
|
@ -3,7 +3,7 @@ mod tracker;
|
|||||||
|
|
||||||
pub use tracker::Tracker;
|
pub use tracker::Tracker;
|
||||||
|
|
||||||
use futures::stream::BoxStream;
|
use crate::BoxStream;
|
||||||
|
|
||||||
/// A request to listen to external events.
|
/// A request to listen to external events.
|
||||||
///
|
///
|
||||||
@ -168,8 +168,8 @@ pub trait Recipe<Hasher: std::hash::Hasher, Event> {
|
|||||||
/// [`Recipe`]: trait.Recipe.html
|
/// [`Recipe`]: trait.Recipe.html
|
||||||
fn stream(
|
fn stream(
|
||||||
self: Box<Self>,
|
self: Box<Self>,
|
||||||
input: BoxStream<'static, Event>,
|
input: BoxStream<Event>,
|
||||||
) -> BoxStream<'static, Self::Output>;
|
) -> BoxStream<Self::Output>;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Map<Hasher, Event, A, B> {
|
struct Map<Hasher, Event, A, B> {
|
||||||
@ -201,18 +201,16 @@ where
|
|||||||
self.recipe.hash(state);
|
self.recipe.hash(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stream(
|
fn stream(self: Box<Self>, input: BoxStream<E>) -> BoxStream<Self::Output> {
|
||||||
self: Box<Self>,
|
|
||||||
input: BoxStream<'static, E>,
|
|
||||||
) -> futures::stream::BoxStream<'static, Self::Output> {
|
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
|
|
||||||
let mapper = self.mapper;
|
let mapper = self.mapper;
|
||||||
|
|
||||||
|
Box::pin(
|
||||||
self.recipe
|
self.recipe
|
||||||
.stream(input)
|
.stream(input)
|
||||||
.map(move |element| mapper(element))
|
.map(move |element| mapper(element)),
|
||||||
.boxed()
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,17 +241,15 @@ where
|
|||||||
self.recipe.hash(state);
|
self.recipe.hash(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stream(
|
fn stream(self: Box<Self>, input: BoxStream<E>) -> BoxStream<Self::Output> {
|
||||||
self: Box<Self>,
|
|
||||||
input: BoxStream<'static, E>,
|
|
||||||
) -> futures::stream::BoxStream<'static, Self::Output> {
|
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
|
|
||||||
let value = self.value;
|
let value = self.value;
|
||||||
|
|
||||||
|
Box::pin(
|
||||||
self.recipe
|
self.recipe
|
||||||
.stream(input)
|
.stream(input)
|
||||||
.map(move |element| (value.clone(), element))
|
.map(move |element| (value.clone(), element)),
|
||||||
.boxed()
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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};
|
use std::{collections::HashMap, marker::PhantomData};
|
||||||
|
|
||||||
/// A registry of subscription streams.
|
/// A registry of subscription streams.
|
||||||
@ -59,7 +59,7 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
subscription: Subscription<Hasher, Event, Message>,
|
subscription: Subscription<Hasher, Event, Message>,
|
||||||
receiver: Receiver,
|
receiver: Receiver,
|
||||||
) -> Vec<BoxFuture<'static, ()>>
|
) -> Vec<BoxFuture<()>>
|
||||||
where
|
where
|
||||||
Message: 'static + Send,
|
Message: 'static + Send,
|
||||||
Receiver: 'static
|
Receiver: 'static
|
||||||
@ -70,7 +70,7 @@ where
|
|||||||
{
|
{
|
||||||
use futures::{future::FutureExt, stream::StreamExt};
|
use futures::{future::FutureExt, stream::StreamExt};
|
||||||
|
|
||||||
let mut futures = Vec::new();
|
let mut futures: Vec<BoxFuture<()>> = Vec::new();
|
||||||
|
|
||||||
let recipes = subscription.recipes();
|
let recipes = subscription.recipes();
|
||||||
let mut alive = std::collections::HashSet::new();
|
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));
|
self.subscriptions.retain(|id, _| alive.contains(&id));
|
||||||
|
@ -2,7 +2,7 @@ use crate::{
|
|||||||
subscription::{EventStream, Recipe},
|
subscription::{EventStream, Recipe},
|
||||||
Event, Hasher,
|
Event, Hasher,
|
||||||
};
|
};
|
||||||
use iced_futures::futures::stream::BoxStream;
|
use iced_futures::BoxStream;
|
||||||
|
|
||||||
pub struct Events;
|
pub struct Events;
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ impl Recipe<Hasher, Event> for Events {
|
|||||||
fn stream(
|
fn stream(
|
||||||
self: Box<Self>,
|
self: Box<Self>,
|
||||||
event_stream: EventStream,
|
event_stream: EventStream,
|
||||||
) -> BoxStream<'static, Self::Output> {
|
) -> BoxStream<Self::Output> {
|
||||||
event_stream
|
event_stream
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user