runestick/
future.rs

1use crate::{
2    FromValue, InstallWith, Mut, Named, RawMut, RawRef, RawStr, Ref, Shared, ToValue,
3    UnsafeFromValue, Value, VmError,
4};
5use pin_project::pin_project;
6use std::fmt;
7/// A future which can be unsafely polled.
8use std::future;
9use std::pin::Pin;
10use std::task::{Context, Poll};
11
12/// dyn future alias.
13type DynFuture = dyn future::Future<Output = Result<Value, VmError>> + 'static;
14
15/// A type-erased future that can only be unsafely polled in combination with
16/// the virtual machine that created it.
17pub struct Future {
18    future: Option<Pin<Box<DynFuture>>>,
19}
20
21impl Future {
22    /// Construct a new wrapped future.
23    pub fn new<T, O>(future: T) -> Self
24    where
25        T: 'static + future::Future<Output = Result<O, VmError>>,
26        O: ToValue,
27    {
28        Self {
29            future: Some(Box::pin(async move {
30                let value = future.await?;
31                Ok(value.to_value()?)
32            })),
33        }
34    }
35
36    /// Check if future is completed.
37    ///
38    /// This will prevent it from being used in a select expression.
39    pub fn is_completed(&self) -> bool {
40        self.future.is_none()
41    }
42}
43
44impl future::Future for Future {
45    type Output = Result<Value, VmError>;
46
47    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<Value, VmError>> {
48        let this = self.get_mut();
49        let mut future = this.future.take().expect("futures can only be polled once");
50
51        match future.as_mut().poll(cx) {
52            Poll::Ready(result) => Poll::Ready(result),
53            Poll::Pending => {
54                this.future = Some(future);
55                Poll::Pending
56            }
57        }
58    }
59}
60
61impl fmt::Debug for Future {
62    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
63        fmt.debug_struct("Future")
64            .field("is_completed", &self.future.is_none())
65            .finish()
66    }
67}
68
69/// Future wrapper used to keep track of associated data.
70#[pin_project]
71pub struct SelectFuture<T, F> {
72    data: T,
73    #[pin]
74    future: F,
75}
76
77impl<T, F> SelectFuture<T, F> {
78    /// Construct a new select future.
79    pub fn new(data: T, future: F) -> Self {
80        Self { data, future }
81    }
82}
83
84impl<T, F> future::Future for SelectFuture<T, F>
85where
86    T: Copy,
87    F: future::Future<Output = Result<Value, VmError>>,
88{
89    type Output = Result<(T, Value), VmError>;
90
91    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
92        let this = self.project();
93        let result = this.future.poll(cx);
94
95        match result {
96            Poll::Ready(result) => match result {
97                Ok(value) => Poll::Ready(Ok((*this.data, value))),
98                Err(e) => Poll::Ready(Err(e)),
99            },
100            Poll::Pending => Poll::Pending,
101        }
102    }
103}
104
105impl FromValue for Shared<Future> {
106    fn from_value(value: Value) -> Result<Self, VmError> {
107        value.into_shared_future()
108    }
109}
110
111impl FromValue for Future {
112    fn from_value(value: Value) -> Result<Self, VmError> {
113        value.into_future()
114    }
115}
116
117impl UnsafeFromValue for &Future {
118    type Output = *const Future;
119    type Guard = RawRef;
120
121    fn from_value(value: Value) -> Result<(Self::Output, Self::Guard), VmError> {
122        let future = value.into_shared_future()?;
123        let (future, guard) = Ref::into_raw(future.into_ref()?);
124        Ok((future, guard))
125    }
126
127    unsafe fn unsafe_coerce(output: Self::Output) -> Self {
128        &*output
129    }
130}
131
132impl UnsafeFromValue for &mut Future {
133    type Output = *mut Future;
134    type Guard = RawMut;
135
136    fn from_value(value: Value) -> Result<(Self::Output, Self::Guard), VmError> {
137        let future = value.into_shared_future()?;
138        Ok(Mut::into_raw(future.into_mut()?))
139    }
140
141    unsafe fn unsafe_coerce(output: Self::Output) -> Self {
142        &mut *output
143    }
144}
145
146impl Named for Future {
147    const BASE_NAME: RawStr = RawStr::from_str("Future");
148}
149
150impl InstallWith for Future {}