1use core::fmt;
2use core::future;
3use core::pin::Pin;
4use core::ptr::NonNull;
5use core::task::{Context, Poll};
6
7use crate::alloc::alloc::Global;
8use crate::alloc::{self, Box};
9use crate::runtime::vm_execution::VmResumeOwned;
10use crate::runtime::{Dismantle, Handover, ToValue, Value, Vm, VmError, VmErrorKind, VmExecution};
11use crate::Any;
12
13use pin_project::pin_project;
14
15struct Vtable {
17 poll: unsafe fn(*mut (), cx: &mut Context<'_>) -> Poll<Result<Value, VmError>>,
18 drop: unsafe fn(*mut ()),
19 dismantle: Option<unsafe fn(*mut (), &mut Handover<'_>)>,
22 is_unstarted: Option<unsafe fn(*mut ()) -> bool>,
27 take_vm: Option<unsafe fn(*mut ()) -> Vm>,
30}
31
32#[derive(Any)]
35#[rune(crate)]
36#[rune(item = ::std::future, dismantle)]
37pub struct Future {
38 future: Option<NonNull<()>>,
39 vtable: &'static Vtable,
40}
41
42impl Future {
43 pub(crate) fn new<T, O>(future: T) -> alloc::Result<Self>
45 where
46 T: 'static + future::Future<Output = Result<O, VmError>>,
47 O: ToValue,
48 {
49 let (future, Global) = Box::into_raw_with_allocator(Box::try_new(future)?);
50
51 let future = unsafe { NonNull::new_unchecked(future).cast() };
52
53 Ok(Self {
54 future: Some(future),
55 vtable: &Vtable {
56 poll: |future, cx| unsafe {
57 match Pin::new_unchecked(&mut *future.cast::<T>()).poll(cx) {
58 Poll::Pending => Poll::Pending,
59 Poll::Ready(result) => match result {
60 Ok(result) => match result.to_value() {
61 Ok(value) => Poll::Ready(Ok(value)),
62 Err(err) => Poll::Ready(Err(err.into())),
63 },
64 Err(err) => Poll::Ready(Err(err)),
65 },
66 }
67 },
68 drop: |future| unsafe {
69 _ = Box::from_raw_in(future.cast::<T>(), Global);
70 },
71 dismantle: None,
72 is_unstarted: None,
73 take_vm: None,
74 },
75 })
76 }
77
78 pub(crate) fn from_execution(execution: VmExecution<Vm>) -> alloc::Result<Self> {
86 let future = Box::try_new(VmResumeOwned::new(execution))?;
87 let (future, Global) = Box::into_raw_with_allocator(future);
88
89 let future = unsafe { NonNull::new_unchecked(future).cast() };
90
91 Ok(Self {
92 future: Some(future),
93 vtable: &Vtable {
94 poll: |future, cx| unsafe {
95 let future = Pin::new_unchecked(&mut *future.cast::<VmResumeOwned>());
96 future::Future::poll(future, cx)
97 },
98 drop: |future| unsafe {
99 _ = Box::from_raw_in(future.cast::<VmResumeOwned>(), Global);
100 },
101 dismantle: Some(|future, out| unsafe {
102 (*future.cast::<VmResumeOwned>()).dismantle(out)
103 }),
104 is_unstarted: Some(|future| unsafe {
105 (*future.cast::<VmResumeOwned>()).is_unstarted()
106 }),
107 take_vm: Some(|future| unsafe { (*future.cast::<VmResumeOwned>()).take_vm() }),
108 },
109 })
110 }
111
112 pub(crate) fn take_unstarted_vm(&mut self) -> Option<Vm> {
122 let (Some(future), Some(is_unstarted), Some(take_vm)) =
123 (self.future, self.vtable.is_unstarted, self.vtable.take_vm)
124 else {
125 return None;
126 };
127
128 unsafe {
132 if !is_unstarted(future.as_ptr()) {
133 return None;
134 }
135
136 let vm = take_vm(future.as_ptr());
137 self.future = None;
138 (self.vtable.drop)(future.as_ptr());
139 Some(vm)
140 }
141 }
142
143 pub fn is_completed(&self) -> bool {
147 self.future.is_none()
148 }
149}
150
151impl future::Future for Future {
152 type Output = Result<Value, VmError>;
153
154 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<Value, VmError>> {
155 unsafe {
156 let this = self.get_unchecked_mut();
157
158 let Some(future) = this.future else {
159 return Poll::Ready(Err(VmError::new(VmErrorKind::FutureCompleted)));
160 };
161
162 match (this.vtable.poll)(future.as_ptr(), cx) {
163 Poll::Ready(result) => {
164 this.future = None;
165 (this.vtable.drop)(future.as_ptr());
166 Poll::Ready(result)
167 }
168 Poll::Pending => Poll::Pending,
169 }
170 }
171 }
172}
173
174impl Dismantle for Future {
177 fn dismantle(&mut self, out: &mut Handover<'_>) {
178 let (Some(future), Some(dismantle)) = (self.future, self.vtable.dismantle) else {
179 return;
180 };
181
182 unsafe { dismantle(future.as_ptr(), out) }
184 }
185}
186
187impl Drop for Future {
188 fn drop(&mut self) {
189 unsafe {
190 if let Some(future) = self.future.take() {
191 (self.vtable.drop)(future.as_ptr());
192 }
193 }
194 }
195}
196
197impl fmt::Debug for Future {
198 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
199 fmt.debug_struct("Future")
200 .field("is_completed", &self.future.is_none())
201 .finish_non_exhaustive()
202 }
203}
204
205#[pin_project]
207pub struct SelectFuture<T, F> {
208 data: T,
209 #[pin]
210 future: F,
211}
212
213impl<T, F> SelectFuture<T, F> {
214 pub fn new(data: T, future: F) -> Self {
216 Self { data, future }
217 }
218}
219
220impl<T, F> future::Future for SelectFuture<T, F>
221where
222 T: Copy,
223 F: future::Future<Output = Result<Value, VmError>>,
224{
225 type Output = Result<(T, Value), VmError>;
226
227 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
228 let this = self.project();
229 let result = this.future.poll(cx);
230
231 match result {
232 Poll::Ready(result) => match result {
233 Ok(value) => Poll::Ready(Ok((*this.data, value))),
234 Err(error) => Poll::Ready(Err(error)),
235 },
236 Poll::Pending => Poll::Pending,
237 }
238 }
239}