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

ambee/giterated

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

Spinning

Amber - ⁨1⁩ year ago

parent: tbd commit: ⁨1788060

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