hakuban 0.7.2

Data-object sharing library
Documentation
#![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() };
		//TODO: no need to do it on every call?
		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>>>, //, wake_callback: extern "C" fn(*const c_void), wake_callback_userdata: *const c_void
}


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>>>, //, wake_callback: extern "C" fn(*const c_void), wake_callback_userdata: *const c_void
}


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() };
		//TODO: no need to do it on every call?
		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) });
}