use std::cell::{Cell, RefCell};
use std::future::Future;
use std::pin::Pin;
use std::rc::Rc;
use std::sync::atomic::AtomicBool;
use std::task::Context;
use self::waker::WakerState;
#[cfg_attr(not(target_arch = "wasm32"), allow(unused_variables, unreachable_code))]
pub fn spawn<F: 'static + Future<Output = ()>>(future: F) {
#[cfg(not(target_arch = "wasm32"))]
panic!("Cannot be run outside of wasm!"); let pinned_future = Box::pin(future);
let waker_state = Rc::new(WakerState {
future: RefCell::new(pinned_future),
previous_trap: Cell::new(false),
});
let waker = waker::waker(Rc::clone(&waker_state));
let _ = waker_state
.future
.borrow_mut()
.as_mut()
.poll(&mut Context::from_waker(&waker));
}
pub(crate) static CLEANUP: AtomicBool = AtomicBool::new(false);
mod waker {
use super::*;
use std::{
rc::Rc,
sync::atomic::Ordering,
task::{RawWaker, RawWakerVTable, Waker},
};
pub(crate) struct WakerState {
pub future: RefCell<Pin<Box<dyn Future<Output = ()>>>>,
pub previous_trap: Cell<bool>,
}
static MY_VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop);
unsafe fn raw_waker(ptr: *const ()) -> RawWaker {
RawWaker::new(ptr, &MY_VTABLE)
}
unsafe fn clone(ptr: *const ()) -> RawWaker {
unsafe {
Rc::increment_strong_count(ptr);
raw_waker(ptr)
}
}
unsafe fn wake(ptr: *const ()) {
let state = unsafe { Rc::from_raw(ptr as *const WakerState) };
if super::CLEANUP.load(Ordering::Relaxed) {
state.previous_trap.set(true);
} else if state.previous_trap.get() {
crate::trap("Call already trapped");
} else {
let waker = waker(Rc::clone(&state));
let Ok(mut borrow) = state.future.try_borrow_mut() else {
return;
};
let pinned_future = borrow.as_mut();
let _ = pinned_future.poll(&mut Context::from_waker(&waker));
}
}
unsafe fn wake_by_ref(ptr: *const ()) {
unsafe {
Rc::increment_strong_count(ptr as *const WakerState);
wake(ptr);
}
}
unsafe fn drop(ptr: *const ()) {
unsafe {
Rc::from_raw(ptr as *const WakerState);
}
}
pub(crate) fn waker(state: Rc<WakerState>) -> Waker {
let ptr = Rc::into_raw(state);
unsafe { Waker::from_raw(raw_waker(ptr as *const ())) }
}
}