use futures_core::future::{BoxFuture, Future, LocalBoxFuture};
use futures_executor::{LocalPool, LocalSpawner};
use futures_util::task::{LocalSpawn as _, Spawn as _};
pub trait Runtime {
type Spawner: Spawner;
fn spawner(&self) -> Self::Spawner;
fn exec<Fut>(&mut self, fut: Fut) -> Fut::Output
where
Fut: Future;
}
impl<T: ?Sized> Runtime for &mut T
where
T: Runtime,
{
type Spawner = T::Spawner;
#[inline]
fn spawner(&self) -> Self::Spawner {
(**self).spawner()
}
#[inline]
fn exec<Fut>(&mut self, fut: Fut) -> Fut::Output
where
Fut: Future,
{
(**self).exec(fut)
}
}
impl<T: ?Sized> Runtime for Box<T>
where
T: Runtime,
{
type Spawner = T::Spawner;
#[inline]
fn spawner(&self) -> Self::Spawner {
(**self).spawner()
}
#[inline]
fn exec<Fut>(&mut self, fut: Fut) -> Fut::Output
where
Fut: Future,
{
(**self).exec(fut)
}
}
pub trait Spawner {
fn spawn(&mut self, fut: BoxFuture<'static, ()>) -> anyhow::Result<()>;
fn spawn_local(&mut self, fut: LocalBoxFuture<'static, ()>) -> anyhow::Result<()>;
fn block(&mut self, f: Box<dyn FnOnce() + Send + 'static>) -> anyhow::Result<()>;
}
impl<T: ?Sized> Spawner for &mut T
where
T: Spawner,
{
#[inline]
fn spawn(&mut self, fut: BoxFuture<'static, ()>) -> anyhow::Result<()> {
(**self).spawn(fut)
}
#[inline]
fn spawn_local(&mut self, fut: LocalBoxFuture<'static, ()>) -> anyhow::Result<()> {
(**self).spawn_local(fut)
}
#[inline]
fn block(&mut self, f: Box<dyn FnOnce() + Send + 'static>) -> anyhow::Result<()> {
(**self).block(f)
}
}
impl<T: ?Sized> Spawner for Box<T>
where
T: Spawner,
{
#[inline]
fn spawn(&mut self, fut: BoxFuture<'static, ()>) -> anyhow::Result<()> {
(**self).spawn(fut)
}
#[inline]
fn spawn_local(&mut self, fut: LocalBoxFuture<'static, ()>) -> anyhow::Result<()> {
(**self).spawn_local(fut)
}
#[inline]
fn block(&mut self, f: Box<dyn FnOnce() + Send + 'static>) -> anyhow::Result<()> {
(**self).block(f)
}
}
pub fn default() -> impl Runtime {
DefaultRuntime {
pool: LocalPool::new(),
}
}
struct DefaultRuntime {
pool: LocalPool,
}
struct DefaultSpawner {
spawner: LocalSpawner,
}
impl Runtime for DefaultRuntime {
type Spawner = DefaultSpawner;
#[inline]
fn spawner(&self) -> Self::Spawner {
DefaultSpawner {
spawner: self.pool.spawner(),
}
}
#[inline]
fn exec<Fut>(&mut self, fut: Fut) -> Fut::Output
where
Fut: Future,
{
self.pool.run_until(fut)
}
}
impl Spawner for DefaultSpawner {
fn spawn(&mut self, fut: BoxFuture<'static, ()>) -> anyhow::Result<()> {
self.spawner.spawn_obj(fut.into()).map_err(Into::into)
}
fn spawn_local(&mut self, fut: LocalBoxFuture<'static, ()>) -> anyhow::Result<()> {
self.spawner.spawn_local_obj(fut.into()).map_err(Into::into)
}
fn block(&mut self, f: Box<dyn FnOnce() + Send + 'static>) -> anyhow::Result<()> {
self.spawn_local(Box::pin(async move { f() }))
}
}