executor: add spawner

This allows spawning a task on an executor from outside of it

Fixes #1

Signed-off-by: Marc-Antoine Perennou <Marc-Antoine@Perennou.com>
This commit is contained in:
Marc-Antoine Perennou 2020-07-23 14:57:40 +02:00
parent c7bfd46e99
commit b9c846ec47
1 changed files with 77 additions and 4 deletions

View File

@ -30,6 +30,7 @@
use std::future::Future; use std::future::Future;
use std::pin::Pin; use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
use std::time::Duration; use std::time::Duration;
@ -72,7 +73,7 @@ scoped_thread_local!(static LOCAL_EX: LocalExecutor);
/// ``` /// ```
#[derive(Debug)] #[derive(Debug)]
pub struct Executor { pub struct Executor {
ex: multitask::Executor, ex: Arc<multitask::Executor>,
} }
impl Executor { impl Executor {
@ -81,13 +82,29 @@ impl Executor {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use async_executor::LocalExecutor; /// use async_executor::Executor;
/// ///
/// let local_ex = LocalExecutor::new(); /// let ex = Executor::new();
/// ``` /// ```
pub fn new() -> Executor { pub fn new() -> Executor {
Executor { Executor {
ex: multitask::Executor::new(), ex: Arc::new(multitask::Executor::new()),
}
}
/// Creates a spawner for this executor.
///
/// # Examples
///
/// ```
/// use async_executor::Executor;
///
/// let ex = Executor::new();
/// let spawner = ex.spawner();
/// ```
pub fn spawner(&self) -> Spawner {
Spawner {
ex: self.ex.clone(),
} }
} }
@ -184,6 +201,62 @@ impl Default for Executor {
} }
} }
/// A spawner for a multi-threaded executor.
#[derive(Debug)]
pub struct Spawner {
ex: Arc<multitask::Executor>,
}
impl Spawner {
/// Gets a spawner for the current multi-threaded executor.
///
/// If called from an [`Executor`], returns its [`Spawner`].
///
/// Otherwise, this method panics.
///
/// # Examples
///
/// ```
/// use async_executor::{Executor, Spawner};
///
/// let ex = Executor::new();
///
/// ex.run(async {
/// let spawner = Spawner::current();
/// let task = spawner.spawn(async { 1 + 2 });
/// assert_eq!(task.await, 3);
/// });
/// ```
pub fn current() -> Spawner {
if EX.is_set() {
EX.with(|ex| ex.spawner())
} else {
panic!("`Spawner::current()` must be called from an `Executor`")
}
}
/// Spawns a task onto the executor.
///
/// # Examples
///
/// ```
/// use async_executor::Executor;
///
/// let ex = Executor::new();
/// let spawner = ex.spawner();
///
/// let task = spawner.spawn(async {
/// println!("Hello world");
/// });
/// ```
pub fn spawn<T: Send + 'static>(
&self,
future: impl Future<Output = T> + Send + 'static,
) -> Task<T> {
Task(self.ex.spawn(future))
}
}
/// Single-threaded executor. /// Single-threaded executor.
/// ///
/// The executor can only be run on the thread that created it. /// The executor can only be run on the thread that created it.