#![allow(clippy::not_unsafe_ptr_arg_deref)]
use std::{
future::Future,
pin::Pin,
sync::{Arc, Mutex},
task::Context,
};
use futures::task::ArcWake;
use wasm_bindgen::prelude::wasm_bindgen;
use super::{wasm_result::WasmResult, WasmExchange};
pub struct WasmWaker {
wakers_triggered: Arc<Mutex<Vec<u64>>>,
waker_id: u64,
}
impl ArcWake for WasmWaker {
fn wake_by_ref(arc_self: &Arc<Self>) {
arc_self.wakers_triggered.lock().unwrap().push(arc_self.waker_id);
}
}
pub struct WasmFuture {
future: Pin<Box<dyn Future<Output = WasmResult>>>,
}
impl WasmFuture {
pub(crate) fn new(future: impl Future<Output = WasmResult> + 'static) -> WasmFuture {
WasmFuture { future: Box::pin(future) }
}
fn poll(exchange_pointer: *mut WasmExchange, future_pointer: *mut Self, waker_id: u64) -> WasmResult {
let exchange = unsafe { exchange_pointer.as_mut().unwrap() };
let future = unsafe { future_pointer.as_mut().unwrap() };
let waker = futures::task::waker(Arc::new(WasmWaker { wakers_triggered: exchange.wakers_triggered.clone(), waker_id }));
let mut cx = Context::from_waker(&waker);
match future.future.as_mut().poll(&mut cx) {
std::task::Poll::Ready(result) => result,
std::task::Poll::Pending => WasmResult::pending(),
}
}
}
#[wasm_bindgen]
pub fn hakuban_future_poll(exchange_pointer: *mut WasmExchange, future_pointer: *mut WasmFuture, waker_id: u64) -> WasmResult {
WasmFuture::poll(exchange_pointer, future_pointer, waker_id)
}
#[wasm_bindgen]
pub fn hakuban_future_drop(future: *mut WasmFuture) {
drop(unsafe { Box::from_raw(future) });
}