use std::future::Future;
use tokio::task::JoinHandle;
pub trait Executor: Clone + Send + Sync + 'static {
fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
where
F: Future + Send + 'static,
F::Output: Send + 'static;
}
impl Executor for tokio::runtime::Handle {
fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
where
F: Future + Send + 'static,
F::Output: Send + 'static,
{
tokio::runtime::Handle::spawn(self, future)
}
}
#[derive(Clone)]
pub struct BlockingExecutor {
handle: tokio::runtime::Handle,
}
impl BlockingExecutor {
pub fn new(handle: tokio::runtime::Handle) -> Self {
Self { handle }
}
pub fn current() -> Self {
Self::new(tokio::runtime::Handle::current())
}
}
impl Executor for BlockingExecutor {
fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
where
F: Future + Send + 'static,
F::Output: Send + 'static,
{
self.handle.spawn(future)
}
}
#[derive(Clone)]
pub struct CurrentRuntime {
handle: tokio::runtime::Handle,
}
impl CurrentRuntime {
pub fn new() -> Self {
Self {
handle: tokio::runtime::Handle::current(),
}
}
}
impl Default for CurrentRuntime {
fn default() -> Self {
Self::new()
}
}
impl Executor for CurrentRuntime {
fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
where
F: Future + Send + 'static,
F::Output: Send + 'static,
{
self.handle.spawn(future)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_handle_executor() {
let handle = tokio::runtime::Handle::current();
let join = handle.spawn(async { 42 });
assert_eq!(join.await.unwrap(), 42);
}
#[tokio::test]
async fn test_current_runtime_executor() {
let executor = CurrentRuntime::new();
let join = executor.spawn(async { 42 });
assert_eq!(join.await.unwrap(), 42);
}
#[tokio::test]
async fn test_blocking_executor() {
let executor = BlockingExecutor::current();
let join = executor.spawn(async { 42 });
assert_eq!(join.await.unwrap(), 42);
}
}