Drop Send in Command and Executor on Wasm
This commit is contained in:
parent
9a06e481b7
commit
ca213922d0
@ -1,100 +1,11 @@
|
|||||||
use futures::future::{BoxFuture, Future, FutureExt};
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
mod native;
|
||||||
|
|
||||||
/// A collection of async operations.
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
///
|
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<'static, T>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Command<T> {
|
#[cfg(target_arch = "wasm32")]
|
||||||
/// Creates an empty [`Command`].
|
mod web;
|
||||||
///
|
|
||||||
/// 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.
|
#[cfg(target_arch = "wasm32")]
|
||||||
///
|
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![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 exectued 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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
100
futures/src/command/native.rs
Normal file
100
futures/src/command/native.rs
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
101
futures/src/command/web.rs
Normal file
101
futures/src/command/web.rs
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
//! Choose your preferred executor to power a runtime.
|
//! Choose your preferred executor to power a runtime.
|
||||||
mod null;
|
mod null;
|
||||||
|
|
||||||
#[cfg(feature = "thread-pool")]
|
#[cfg(all(not(target_arch = "wasm32"), feature = "thread-pool"))]
|
||||||
mod thread_pool;
|
mod thread_pool;
|
||||||
|
|
||||||
#[cfg(all(not(target_arch = "wasm32"), feature = "tokio"))]
|
#[cfg(all(not(target_arch = "wasm32"), feature = "tokio"))]
|
||||||
@ -15,7 +15,7 @@ mod wasm_bindgen;
|
|||||||
|
|
||||||
pub use null::Null;
|
pub use null::Null;
|
||||||
|
|
||||||
#[cfg(feature = "thread-pool")]
|
#[cfg(all(not(target_arch = "wasm32"), feature = "thread-pool"))]
|
||||||
pub use thread_pool::ThreadPool;
|
pub use thread_pool::ThreadPool;
|
||||||
|
|
||||||
#[cfg(all(not(target_arch = "wasm32"), feature = "tokio"))]
|
#[cfg(all(not(target_arch = "wasm32"), feature = "tokio"))]
|
||||||
@ -41,8 +41,15 @@ pub trait Executor: Sized {
|
|||||||
/// Spawns a future in the [`Executor`].
|
/// Spawns a future in the [`Executor`].
|
||||||
///
|
///
|
||||||
/// [`Executor`]: trait.Executor.html
|
/// [`Executor`]: trait.Executor.html
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
fn spawn(&self, future: impl Future<Output = ()> + Send + 'static);
|
fn spawn(&self, future: impl Future<Output = ()> + Send + 'static);
|
||||||
|
|
||||||
|
/// Spawns a local future in the [`Executor`].
|
||||||
|
///
|
||||||
|
/// [`Executor`]: trait.Executor.html
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
fn spawn(&self, future: impl Future<Output = ()> + 'static);
|
||||||
|
|
||||||
/// Runs the given closure inside the [`Executor`].
|
/// Runs the given closure inside the [`Executor`].
|
||||||
///
|
///
|
||||||
/// Some executors, like `tokio`, require some global state to be in place
|
/// Some executors, like `tokio`, require some global state to be in place
|
||||||
|
|||||||
@ -11,5 +11,9 @@ impl Executor for Null {
|
|||||||
Ok(Self)
|
Ok(Self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
fn spawn(&self, _future: impl Future<Output = ()> + Send + 'static) {}
|
fn spawn(&self, _future: impl Future<Output = ()> + Send + 'static) {}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
fn spawn(&self, _future: impl Future<Output = ()> + 'static) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,10 +9,7 @@ impl Executor for WasmBindgen {
|
|||||||
Ok(Self)
|
Ok(Self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn(
|
fn spawn(&self, future: impl futures::Future<Output = ()> + 'static) {
|
||||||
&self,
|
|
||||||
future: impl futures::Future<Output = ()> + Send + 'static,
|
|
||||||
) {
|
|
||||||
wasm_bindgen_futures::spawn_local(future);
|
wasm_bindgen_futures::spawn_local(future);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -73,11 +73,13 @@ where
|
|||||||
for future in futures {
|
for future in futures {
|
||||||
let mut sender = self.sender.clone();
|
let mut sender = self.sender.clone();
|
||||||
|
|
||||||
self.executor.spawn(future.then(|message| async move {
|
let future = future.then(|message| async move {
|
||||||
let _ = sender.send(message).await;
|
let _ = sender.send(message).await;
|
||||||
|
|
||||||
()
|
()
|
||||||
}));
|
});
|
||||||
|
|
||||||
|
self.executor.spawn(future);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,8 @@ mod platform {
|
|||||||
|
|
||||||
/// A default cross-platform executor.
|
/// A default cross-platform executor.
|
||||||
///
|
///
|
||||||
/// - On native platforms, it will use a `iced_futures::executor::ThreadPool`.
|
/// - On native platforms, it will use a
|
||||||
|
/// `iced_futures::executor::ThreadPool`.
|
||||||
/// - On the Web, it will use `iced_futures::executor::WasmBindgen`.
|
/// - On the Web, it will use `iced_futures::executor::WasmBindgen`.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Default(ThreadPool);
|
pub struct Default(ThreadPool);
|
||||||
@ -34,7 +35,8 @@ mod platform {
|
|||||||
|
|
||||||
/// A default cross-platform executor.
|
/// A default cross-platform executor.
|
||||||
///
|
///
|
||||||
/// - On native platforms, it will use a `iced_futures::executor::ThreadPool`.
|
/// - On native platforms, it will use a
|
||||||
|
/// `iced_futures::executor::ThreadPool`.
|
||||||
/// - On the Web, it will use `iced_futures::executor::WasmBindgen`.
|
/// - On the Web, it will use `iced_futures::executor::WasmBindgen`.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Default(WasmBindgen);
|
pub struct Default(WasmBindgen);
|
||||||
@ -44,10 +46,7 @@ mod platform {
|
|||||||
Ok(Default(WasmBindgen::new()?))
|
Ok(Default(WasmBindgen::new()?))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn(
|
fn spawn(&self, future: impl futures::Future<Output = ()> + 'static) {
|
||||||
&self,
|
|
||||||
future: impl futures::Future<Output = ()> + Send + 'static,
|
|
||||||
) {
|
|
||||||
self.0.spawn(future);
|
self.0.spawn(future);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user