fp_bindgen_support/guest/async/
mod.rs

1mod queue;
2pub mod task;
3use crate::common::{
4    mem::{from_fat_ptr, FatPtr},
5    r#async::{AsyncValue, FUTURE_STATUS_PENDING, FUTURE_STATUS_READY},
6};
7use once_cell::unsync::Lazy;
8use std::collections::BTreeMap;
9use std::future::Future;
10use std::ptr::{read_volatile, write_volatile};
11use std::task::{Context, Poll, Waker};
12
13static mut WAKERS: Lazy<BTreeMap<FatPtr, Waker>> = Lazy::new(BTreeMap::new);
14
15/// Represents a future value that will be resolved by the host runtime.
16pub struct HostFuture {
17    ptr: FatPtr,
18}
19
20impl HostFuture {
21    /// # Safety
22    ///
23    /// This function is only safe if passed a valid pointer to an `AsyncValue`
24    /// created by the host. Only a single `HostFuture` may be created from such
25    /// a pointer.
26    pub unsafe fn new(async_value_ptr: FatPtr) -> Self {
27        Self {
28            ptr: async_value_ptr,
29        }
30    }
31}
32
33impl Future for HostFuture {
34    type Output = FatPtr;
35
36    fn poll(self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
37        let (ptr, _) = from_fat_ptr(self.ptr);
38        let async_value = unsafe { read_volatile(ptr as *const AsyncValue) };
39        match async_value.status {
40            FUTURE_STATUS_PENDING => {
41                unsafe {
42                    WAKERS.insert(self.ptr, cx.waker().clone());
43                }
44                Poll::Pending
45            }
46            FUTURE_STATUS_READY => Poll::Ready(async_value.buffer_ptr()),
47            status => panic!("Unexpected status: {}", status),
48        }
49    }
50}
51
52#[doc(hidden)]
53#[no_mangle]
54pub unsafe fn __fp_guest_resolve_async_value(async_value_fat_ptr: FatPtr, result_ptr: FatPtr) {
55    // First assign the result ptr and mark the async value as ready:
56    let (ptr, len) = from_fat_ptr(result_ptr);
57    let (async_value_ptr, _) = from_fat_ptr(async_value_fat_ptr);
58    write_volatile(
59        async_value_ptr as *mut AsyncValue,
60        AsyncValue {
61            status: FUTURE_STATUS_READY,
62            ptr: ptr as u32,
63            len,
64        },
65    );
66
67    if let Some(waker) = WAKERS.remove(&async_value_fat_ptr) {
68        waker.wake();
69    }
70}
71
72#[link(wasm_import_module = "fp")]
73extern "C" {
74    fn __fp_host_resolve_async_value(async_value_ptr: FatPtr, result_ptr: FatPtr);
75}
76
77pub fn host_resolve_async_value(async_value_ptr: FatPtr, result_ptr: FatPtr) {
78    unsafe { __fp_host_resolve_async_value(async_value_ptr, result_ptr) }
79}