use futures_util::future::BoxFuture; use futures_util::FutureExt; use giterated_abi::{FfiFuture, FfiValue, FfiValueMut, RuntimeFuturePoll}; use std::{ cell::UnsafeCell, future::Future, marker::PhantomData, mem::transmute, task::{Context, RawWaker, RawWakerVTable, Waker}, }; use crate::{callback::RuntimeState, new_stack::PluginState, FFIBox}; #[repr(C)] pub struct RuntimeWakerCallback { callback: PluginState, waker_func: unsafe extern "C" fn(PluginState), } pub struct WakerState { waker: Waker, } unsafe extern "C" fn wake(_waker: PluginState) {} pub struct LocalRuntimeFuture { inner: BoxFuture<'static, Output>, runtime_future: UnsafeCell>, } unsafe impl Send for LocalRuntimeFuture where Output: Send {} unsafe impl Sync for LocalRuntimeFuture where Output: Sync {} impl LocalRuntimeFuture { pub fn finalize(self) {} pub fn into_runtime(&self) -> FfiFuture { todo!() } } pub trait RuntimeFuturesExt { fn spawn_future + Send + Sync + 'static>( &self, future: F, ) -> RuntimeFuture; } impl RuntimeFuturesExt for RuntimeState { fn spawn_future + Send + Sync + 'static>( &self, future: F, ) -> RuntimeFuture { let type_eraser = async move { let result = future.await; FFIBox::from_box(Box::new(result)).untyped() }; let runtime_future = unsafe { FfiFuture::from_raw(poll_local, type_eraser.boxed()) }; RuntimeFuture(runtime_future) } } unsafe extern "C" fn poll_local( _future: FfiValueMut>, mut future_state: FfiValueMut<()>, ) -> RuntimeFuturePoll { let mut future_state: FfiValueMut>> = transmute(future_state); let runtime_future = future_state.as_ref(); let raw_waker = RawWaker::new( Box::into_raw(Box::new(runtime_future)) as *const (), &RUNTIME_FUTURE_WAKER_VTABLE, ); let waker = unsafe { Waker::from_raw(raw_waker) }; // SAFETY: Pretty sure this has to be static lol let poll_result = future_state.poll_unpin(&mut Context::from_waker(&waker)); match poll_result { std::task::Poll::Ready(result) => RuntimeFuturePoll::Ready(result), std::task::Poll::Pending => RuntimeFuturePoll::Pending, } } pub static RUNTIME_FUTURE_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new( runtime_waker_vtable::waker_clone, runtime_waker_vtable::waker_wake, runtime_waker_vtable::waker_wake_by_ref, runtime_waker_vtable::waker_drop, ); mod runtime_waker_vtable { use std::task::RawWaker; pub unsafe fn waker_clone(_data: *const ()) -> RawWaker { todo!() } pub unsafe fn waker_wake(_data: *const ()) { todo!() } pub unsafe fn waker_wake_by_ref(_data: *const ()) { todo!() } pub unsafe fn waker_drop(_data: *const ()) { // no-op } } #[repr(transparent)] pub struct RuntimeFuture(FfiFuture); /// Allows for a remote future to be polled on the target. /// /// The target can be the host or a plugin, but the future should only be polled by one /// source. impl Future for RuntimeFuture { type Output = Output; fn poll( mut self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>, ) -> std::task::Poll { let waker_state = WakerState { waker: cx.waker().clone(), }; let waker_state = PluginState::from(waker_state); unsafe { self.0.write_waker(wake_local, waker_state) }; match unsafe { self.0.poll() } { RuntimeFuturePoll::Ready(result) => { let result: FfiValue = unsafe { transmute(result) }; std::task::Poll::Ready(result.take()) } RuntimeFuturePoll::Pending => std::task::Poll::Pending, } } } unsafe extern "C" fn wake_local(future: FfiValueMut>, state: FfiValueMut<()>) { todo!() }