use crate::{debug_state, Executor, LocalExecutor, State};
use async_task::{Builder, Runnable, Task};
use slab::Slab;
use std::{
cell::UnsafeCell,
fmt,
future::Future,
marker::PhantomData,
panic::{RefUnwindSafe, UnwindSafe},
};
impl Executor<'static> {
pub fn leak(self) -> &'static StaticExecutor {
let ptr = self.state_ptr();
let state: &'static State = unsafe { &*ptr };
std::mem::forget(self);
let mut active = state.active.lock().unwrap();
if !active.is_empty() {
for waker in active.drain() {
waker.wake();
}
*active = Slab::new();
}
let static_executor: &'static StaticExecutor = unsafe { std::mem::transmute(state) };
static_executor
}
}
impl LocalExecutor<'static> {
pub fn leak(self) -> &'static StaticLocalExecutor {
let ptr = self.inner.state_ptr();
let state: &'static State = unsafe { &*ptr };
std::mem::forget(self);
let mut active = state.active.lock().unwrap();
if !active.is_empty() {
for waker in active.drain() {
waker.wake();
}
*active = Slab::new();
}
let static_executor: &'static StaticLocalExecutor = unsafe { std::mem::transmute(state) };
static_executor
}
}
#[repr(transparent)]
pub struct StaticExecutor {
state: State,
}
unsafe impl Send for StaticExecutor {}
unsafe impl Sync for StaticExecutor {}
impl UnwindSafe for StaticExecutor {}
impl RefUnwindSafe for StaticExecutor {}
impl fmt::Debug for StaticExecutor {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
debug_state(&self.state, "StaticExecutor", f)
}
}
impl StaticExecutor {
pub const fn new() -> Self {
Self {
state: State::new(),
}
}
pub fn spawn<T: Send + 'static>(
&'static self,
future: impl Future<Output = T> + Send + 'static,
) -> Task<T> {
let (runnable, task) = Builder::new()
.propagate_panic(true)
.spawn(|()| future, self.schedule());
runnable.schedule();
task
}
pub unsafe fn spawn_scoped<'a, T: Send + 'a>(
&'static self,
future: impl Future<Output = T> + Send + 'a,
) -> Task<T> {
let (runnable, task) = unsafe {
Builder::new()
.propagate_panic(true)
.spawn_unchecked(|()| future, self.schedule())
};
runnable.schedule();
task
}
pub fn try_tick(&self) -> bool {
self.state.try_tick()
}
pub async fn tick(&self) {
self.state.tick().await;
}
pub async fn run<T>(&self, future: impl Future<Output = T>) -> T {
self.state.run(future).await
}
fn schedule(&'static self) -> impl Fn(Runnable) + Send + Sync + 'static {
let state: &'static State = &self.state;
move |runnable| {
state.queue.push(runnable).unwrap();
state.notify();
}
}
}
impl Default for StaticExecutor {
fn default() -> Self {
Self::new()
}
}
#[repr(transparent)]
pub struct StaticLocalExecutor {
state: State,
marker_: PhantomData<UnsafeCell<()>>,
}
impl UnwindSafe for StaticLocalExecutor {}
impl RefUnwindSafe for StaticLocalExecutor {}
impl fmt::Debug for StaticLocalExecutor {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
debug_state(&self.state, "StaticLocalExecutor", f)
}
}
impl StaticLocalExecutor {
pub const fn new() -> Self {
Self {
state: State::new(),
marker_: PhantomData,
}
}
pub fn spawn<T: 'static>(&'static self, future: impl Future<Output = T> + 'static) -> Task<T> {
let (runnable, task) = Builder::new()
.propagate_panic(true)
.spawn_local(|()| future, self.schedule());
runnable.schedule();
task
}
pub unsafe fn spawn_scoped<'a, T: 'a>(
&'static self,
future: impl Future<Output = T> + 'a,
) -> Task<T> {
let (runnable, task) = unsafe {
Builder::new()
.propagate_panic(true)
.spawn_unchecked(|()| future, self.schedule())
};
runnable.schedule();
task
}
pub fn try_tick(&self) -> bool {
self.state.try_tick()
}
pub async fn tick(&self) {
self.state.tick().await;
}
pub async fn run<T>(&self, future: impl Future<Output = T>) -> T {
self.state.run(future).await
}
fn schedule(&'static self) -> impl Fn(Runnable) + Send + Sync + 'static {
let state: &'static State = &self.state;
move |runnable| {
state.queue.push(runnable).unwrap();
state.notify();
}
}
}
impl Default for StaticLocalExecutor {
fn default() -> Self {
Self::new()
}
}