use std::cell::RefCell;
use std::future::Future;
use std::mem;
use std::pin::Pin;
use std::rc::Rc;
use std::sync::Arc;
use std::task::*;
#[cfg(target_arch = "wasm32")]
#[link(wasm_import_module = "canonical_abi")]
extern "C" {
pub fn async_export_done(ctx: i32, ptr: i32);
}
#[cfg(not(target_arch = "wasm32"))]
pub unsafe extern "C" fn async_export_done(_ctx: i32, _ptr: i32) {
panic!("only supported on wasm");
}
struct PollingWaker {
state: RefCell<State>,
}
enum State {
Waiting(Pin<Box<dyn Future<Output = ()>>>),
Polling,
Woken,
}
#[cfg(not(target_feature = "atomics"))]
unsafe impl Send for PollingWaker {}
#[cfg(not(target_feature = "atomics"))]
unsafe impl Sync for PollingWaker {}
pub fn execute(future: impl Future<Output = ()> + 'static) {
let waker = Arc::new(PollingWaker {
state: RefCell::new(State::Waiting(Box::pin(future))),
});
waker.wake()
}
impl Wake for PollingWaker {
fn wake(self: Arc<Self>) {
let mut state = self.state.borrow_mut();
let mut future = match mem::replace(&mut *state, State::Polling) {
State::Waiting(future) => future,
State::Polling | State::Woken => {
*state = State::Woken;
return;
}
};
drop(state);
let waker = self.clone().into();
let mut cx = Context::from_waker(&waker);
loop {
match future.as_mut().poll(&mut cx) {
Poll::Ready(()) => break,
Poll::Pending => {}
}
let mut state = self.state.borrow_mut();
match *state {
State::Polling => {
*state = State::Waiting(future);
break;
}
State::Woken => {}
State::Waiting(_) => unreachable!(),
}
}
}
}
pub struct Oneshot<T> {
inner: Rc<OneshotInner<T>>,
}
pub struct Sender<T> {
inner: Rc<OneshotInner<T>>,
}
struct OneshotInner<T> {
state: RefCell<OneshotState<T>>,
}
enum OneshotState<T> {
Start,
Waiting(Waker),
Done(T),
}
impl<T> Oneshot<T> {
pub fn new() -> (Oneshot<T>, Sender<T>) {
let inner = Rc::new(OneshotInner {
state: RefCell::new(OneshotState::Start),
});
(
Oneshot {
inner: Rc::clone(&inner),
},
Sender { inner },
)
}
}
impl<T> Future for Oneshot<T> {
type Output = T;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> {
let mut state = self.inner.state.borrow_mut();
match mem::replace(&mut *state, OneshotState::Start) {
OneshotState::Done(t) => Poll::Ready(t),
OneshotState::Waiting(_) | OneshotState::Start => {
*state = OneshotState::Waiting(cx.waker().clone());
Poll::Pending
}
}
}
}
impl<T> Sender<T> {
pub fn into_usize(self) -> usize {
Rc::into_raw(self.inner) as usize
}
pub unsafe fn from_usize(ptr: usize) -> Sender<T> {
Sender {
inner: Rc::from_raw(ptr as *const _),
}
}
pub fn send(self, val: T) {
let mut state = self.inner.state.borrow_mut();
let prev = mem::replace(&mut *state, OneshotState::Done(val));
drop(state);
match prev {
OneshotState::Start => {}
OneshotState::Waiting(waker) => waker.wake(),
OneshotState::Done(_) => unreachable!(),
}
}
}
impl<T> Drop for OneshotInner<T> {
fn drop(&mut self) {
if let OneshotState::Waiting(waker) = &*self.state.borrow() {
waker.wake_by_ref();
}
}
}