#![allow(clippy::not_unsafe_ptr_arg_deref)]
use std::{future::Future, mem::forget, pin::Pin, sync::{Arc, Mutex}, task::{Context, RawWaker, RawWakerVTable, Waker}};
use wasm_bindgen::prelude::wasm_bindgen;
use super::{wasm_result::{WasmResultStatus, WasmResultWithPointer}, WasmLocalExchange, WasmResultWithNothing};
#[derive(Clone)]
pub struct WakeData {
wakers_triggered: Arc<Mutex<Vec<u64>>>,
waker_id: u64,
}
pub static VTABLE: RawWakerVTable = RawWakerVTable::new(
|waker_data_pointer| unsafe {
let wake_data = Arc::from_raw(waker_data_pointer as *const WakeData);
let ret = RawWaker::new(Arc::into_raw(wake_data.clone()) as *const (), &VTABLE);
forget(wake_data);
ret
},
|waker_data_pointer| unsafe {
let wake_data = Arc::from_raw(waker_data_pointer as *const WakeData);
wake_data.wakers_triggered.lock().unwrap().push(wake_data.waker_id);
},
|waker_data_pointer| unsafe {
let wake_data = Arc::from_raw(waker_data_pointer as *const WakeData);
wake_data.wakers_triggered.lock().unwrap().push(wake_data.waker_id);
forget(wake_data);
},
|waker_data_pointer| unsafe {
Arc::from_raw(waker_data_pointer as *const WakeData);
},
);
trait WasmFuture {
type Output;
fn pending() -> Self::Output;
fn future(&mut self) -> &mut Pin<Box<dyn Future<Output = Self::Output>>>;
fn poll(local_exchange_pointer: *mut WasmLocalExchange, future_pointer: *mut Self, waker_id: u64) -> Self::Output {
let local_exchange = unsafe { local_exchange_pointer.as_mut().unwrap() };
let future = unsafe { future_pointer.as_mut().unwrap() };
let wake_lambda = Arc::new(WakeData { wakers_triggered: local_exchange.wakers_triggered.clone(), waker_id });
let raw_waker = RawWaker::new(Arc::into_raw(wake_lambda) as *const (), &VTABLE);
let waker = unsafe { Waker::from_raw(raw_waker) };
let mut cx = Context::from_waker(&waker);
let ret = match future.future().as_mut().poll(&mut cx) {
std::task::Poll::Ready(result) => result,
std::task::Poll::Pending => Self::pending(),
};
ret
}
}
pub struct WasmFutureReturningPointer {
future: Pin<Box<dyn Future<Output = WasmResultWithPointer>>>, }
impl WasmFutureReturningPointer {
pub(crate) fn new(future: impl Future<Output = WasmResultWithPointer> + 'static) -> WasmFutureReturningPointer {
WasmFutureReturningPointer { future: Box::pin(future) }
}
}
impl WasmFuture for WasmFutureReturningPointer {
type Output = WasmResultWithPointer;
fn pending() -> Self::Output {
WasmResultWithPointer::error(WasmResultStatus::Pending)
}
fn future(&mut self) -> &mut Pin<Box<dyn Future<Output = Self::Output>>> {
&mut self.future
}
}
#[wasm_bindgen]
pub fn hakuban_future_returning_pointer_poll(
local_exchange_pointer: *mut WasmLocalExchange, future_pointer: *mut WasmFutureReturningPointer, waker_id: u64,
) -> WasmResultWithPointer {
WasmFutureReturningPointer::poll(local_exchange_pointer, future_pointer, waker_id)
}
#[wasm_bindgen]
pub fn hakuban_future_returning_pointer_drop(future: *mut WasmFutureReturningPointer) {
drop(unsafe { Box::from_raw(future) });
}
pub struct WasmFutureReturningNothing {
future: Pin<Box<dyn Future<Output = WasmResultWithNothing>>>, }
impl WasmFutureReturningNothing {
pub(super) fn new(future: impl Future<Output = WasmResultWithNothing> + 'static) -> WasmFutureReturningNothing {
WasmFutureReturningNothing { future: Box::pin(future) }
}
fn poll(local_exchange_pointer: *mut WasmLocalExchange, future_pointer: *mut WasmFutureReturningNothing, waker_id: u64) -> WasmResultWithNothing {
let local_exchange = unsafe { local_exchange_pointer.as_mut().unwrap() };
let future = unsafe { future_pointer.as_mut().unwrap() };
let wake_lambda = Arc::new(WakeData { wakers_triggered: local_exchange.wakers_triggered.clone(), waker_id });
let raw_waker = RawWaker::new(Arc::into_raw(wake_lambda) as *const (), &VTABLE);
let waker = unsafe { Waker::from_raw(raw_waker) };
let mut cx = Context::from_waker(&waker);
let ret = match future.future.as_mut().poll(&mut cx) {
std::task::Poll::Ready(result) => result,
std::task::Poll::Pending => WasmResultWithNothing::error(WasmResultStatus::Pending),
};
ret
}
}
#[wasm_bindgen]
pub fn hakuban_future_returning_nothing_poll(
local_exchange_pointer: *mut WasmLocalExchange, future_pointer: *mut WasmFutureReturningNothing, waker_id: u64,
) -> WasmResultWithNothing {
WasmFutureReturningNothing::poll(local_exchange_pointer, future_pointer, waker_id)
}
#[wasm_bindgen]
pub fn hakuban_future_returning_nothing_drop(future: *mut WasmFutureReturningNothing) {
drop(unsafe { Box::from_raw(future) });
}