JavaScript is disabled, refresh for a better experience. ambee/giterated

ambee/giterated

Git repository hosting, collaboration, and discovery for the Fediverse.

insanity

Amber - ⁨1⁩ year ago

parent: tbd commit: ⁨6ea28ab

⁨giterated-plugin/src/future.rs⁩ - ⁨4368⁩ bytes
Raw
1 use futures_util::future::BoxFuture;
2 use futures_util::FutureExt;
3 use giterated_abi::{
4 state::State, value_ex::FfiValueUntyped, FfiFuture, FfiValue, FfiValueMut, FfiValueRef,
5 RuntimeFuturePoll,
6 };
7 use std::{
8 cell::UnsafeCell,
9 future::Future,
10 marker::PhantomData,
11 mem::transmute,
12 ops::Deref,
13 task::{Context, RawWaker, RawWakerVTable, Waker},
14 };
15
16 #[repr(C)]
17 pub struct RuntimeWakerCallback {
18 callback: FfiValueUntyped,
19 waker_func: unsafe extern "C" fn(FfiValueUntyped),
20 }
21
22 pub struct WakerState {
23 waker: Waker,
24 }
25
26 unsafe extern "C" fn wake(_waker: FfiValueUntyped) {}
27
28 pub struct LocalRuntimeFuture<Output> {
29 inner: BoxFuture<'static, Output>,
30 runtime_future: UnsafeCell<FfiFuture<Output>>,
31 }
32
33 unsafe impl<Output> Send for LocalRuntimeFuture<Output> where Output: Send {}
34 unsafe impl<Output> Sync for LocalRuntimeFuture<Output> where Output: Sync {}
35
36 impl<Output> LocalRuntimeFuture<Output> {
37 pub fn finalize(self) {}
38
39 pub fn into_runtime(&self) -> FfiFuture<Output> {
40 todo!()
41 }
42 }
43
44 pub trait RuntimeFuturesExt {
45 fn spawn_future<Output, F: Future<Output = Output> + Send + Sync + 'static>(
46 &self,
47 future: F,
48 ) -> RuntimeFuture<Output>;
49 }
50
51 impl RuntimeFuturesExt for State {
52 fn spawn_future<Output, F: Future<Output = Output> + Send + Sync + 'static>(
53 &self,
54 future: F,
55 ) -> RuntimeFuture<Output> {
56 // let type_eraser = async move {
57 // let result = future.await;
58
59 // FFIBox::from_box(Box::new(result)).untyped()
60 // };
61
62 // let runtime_future = unsafe { FfiFuture::from_raw(poll_local, type_eraser.boxed()) };
63
64 // RuntimeFuture(runtime_future)
65
66 todo!()
67 }
68 }
69
70 unsafe extern "C" fn poll_local(
71 _future: FfiValueMut<FfiFuture<()>>,
72 mut future_state: FfiValueMut<()>,
73 ) -> RuntimeFuturePoll {
74 let mut future_state: FfiValueMut<BoxFuture<'static, FfiValue<()>>> = transmute(future_state);
75
76 let runtime_future = future_state.as_ref();
77
78 let raw_waker = RawWaker::new(
79 Box::into_raw(Box::new(runtime_future)) as *const (),
80 &RUNTIME_FUTURE_WAKER_VTABLE,
81 );
82
83 let waker = unsafe { Waker::from_raw(raw_waker) };
84
85 // SAFETY: Pretty sure this has to be static lol
86 let poll_result = future_state.poll_unpin(&mut Context::from_waker(&waker));
87
88 match poll_result {
89 std::task::Poll::Ready(result) => RuntimeFuturePoll::Ready(result),
90 std::task::Poll::Pending => RuntimeFuturePoll::Pending,
91 }
92 }
93
94 pub static RUNTIME_FUTURE_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(
95 runtime_waker_vtable::waker_clone,
96 runtime_waker_vtable::waker_wake,
97 runtime_waker_vtable::waker_wake_by_ref,
98 runtime_waker_vtable::waker_drop,
99 );
100
101 mod runtime_waker_vtable {
102 use std::task::RawWaker;
103
104 pub unsafe fn waker_clone(_data: *const ()) -> RawWaker {
105 todo!()
106 }
107
108 pub unsafe fn waker_wake(_data: *const ()) {
109 todo!()
110 }
111
112 pub unsafe fn waker_wake_by_ref(_data: *const ()) {
113 todo!()
114 }
115
116 pub unsafe fn waker_drop(_data: *const ()) {
117 // no-op
118 }
119 }
120
121 #[repr(transparent)]
122 pub struct RuntimeFuture<Output>(FfiFuture<Output>);
123
124 /// Allows for a remote future to be polled on the target.
125 ///
126 /// The target can be the host or a plugin, but the future should only be polled by one
127 /// source.
128 impl<Output: Unpin> Future for RuntimeFuture<Output> {
129 type Output = Output;
130
131 fn poll(
132 mut self: std::pin::Pin<&mut Self>,
133 cx: &mut Context<'_>,
134 ) -> std::task::Poll<Self::Output> {
135 let waker_state = WakerState {
136 waker: cx.waker().clone(),
137 };
138
139 unsafe { self.0.write_waker(wake_local, waker_state) };
140
141 match unsafe { self.0.poll() } {
142 RuntimeFuturePoll::Ready(result) => {
143 let result: FfiValue<Output> = unsafe { transmute(result) };
144
145 std::task::Poll::Ready(result.take())
146 }
147 RuntimeFuturePoll::Pending => std::task::Poll::Pending,
148 }
149 }
150 }
151
152 /// The function used to wake a local future over FFI
153 unsafe extern "C" fn wake_local(future: FfiValueMut<FfiFuture<()>>) {
154 if let Some(waker) = &future.waker_state {
155 let waker: FfiValueRef<WakerState> = unsafe { transmute(waker.deref()) };
156
157 waker.waker.wake_by_ref();
158 }
159 }
160