1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 //! [`RustFuture`] represents a [`Future`] that can be sent to the foreign code over FFI.
6 //!
7 //! This type is not instantiated directly, but via the procedural macros, such as `#[uniffi::export]`.
8 //!
9 //! # The big picture
10 //!
11 //! We implement async foreign functions using a simplified version of the Future API:
12 //!
13 //! 0. At startup, register a [RustFutureContinuationCallback] by calling
14 //!    rust_future_continuation_callback_set.
15 //! 1. Call the scaffolding function to get a [Handle]
16 //! 2a. In a loop:
17 //!   - Call [rust_future_poll]
18 //!   - Suspend the function until the [rust_future_poll] continuation function is called
19 //!   - If the continuation was function was called with [RustFuturePoll::Ready], then break
20 //!     otherwise continue.
21 //! 2b. If the async function is cancelled, then call [rust_future_cancel].  This causes the
22 //!     continuation function to be called with [RustFuturePoll::Ready] and the [RustFuture] to
23 //!     enter a cancelled state.
24 //! 3. Call [rust_future_complete] to get the result of the future.
25 //! 4. Call [rust_future_free] to free the future, ideally in a finally block.  This:
26 //!    - Releases any resources held by the future
27 //!    - Calls any continuation callbacks that have not been called yet
28 //!
29 //! Note: Technically, the foreign code calls the scaffolding versions of the `rust_future_*`
30 //! functions.  These are generated by the scaffolding macro, specially prefixed, and extern "C",
31 //! and manually monomorphized in the case of [rust_future_complete].  See
32 //! `uniffi_macros/src/setup_scaffolding.rs` for details.
33 //!
34 //! ## How does `Future` work exactly?
35 //!
36 //! A [`Future`] in Rust does nothing. When calling an async function, it just
37 //! returns a `Future` but nothing has happened yet. To start the computation,
38 //! the future must be polled. It returns [`Poll::Ready(r)`][`Poll::Ready`] if
39 //! the result is ready, [`Poll::Pending`] otherwise. `Poll::Pending` basically
40 //! means:
41 //!
42 //! > Please, try to poll me later, maybe the result will be ready!
43 //!
44 //! This model is very different than what other languages do, but it can actually
45 //! be translated quite easily, fortunately for us!
46 //!
47 //! But… wait a minute… who is responsible to poll the `Future` if a `Future` does
48 //! nothing? Well, it's _the executor_. The executor is responsible _to drive_ the
49 //! `Future`: that's where they are polled.
50 //!
51 //! But… wait another minute… how does the executor know when to poll a [`Future`]?
52 //! Does it poll them randomly in an endless loop? Well, no, actually it depends
53 //! on the executor! A well-designed `Future` and executor work as follows.
54 //! Normally, when [`Future::poll`] is called, a [`Context`] argument is
55 //! passed to it. It contains a [`Waker`]. The [`Waker`] is built on top of a
56 //! [`RawWaker`] which implements whatever is necessary. Usually, a waker will
57 //! signal the executor to poll a particular `Future`. A `Future` will clone
58 //! or pass-by-ref the waker to somewhere, as a callback, a completion, a
59 //! function, or anything, to the system that is responsible to notify when a
60 //! task is completed. So, to recap, the waker is _not_ responsible for waking the
61 //! `Future`, it _is_ responsible for _signaling_ the executor that a particular
62 //! `Future` should be polled again. That's why the documentation of
63 //! [`Poll::Pending`] specifies:
64 //!
65 //! > When a function returns `Pending`, the function must also ensure that the
66 //! > current task is scheduled to be awoken when progress can be made.
67 //!
68 //! “awakening” is done by using the `Waker`.
69 //!
70 //! [`Future`]: https://doc.rust-lang.org/std/future/trait.Future.html
71 //! [`Future::poll`]: https://doc.rust-lang.org/std/future/trait.Future.html#tymethod.poll
72 //! [`Pol::Ready`]: https://doc.rust-lang.org/std/task/enum.Poll.html#variant.Ready
73 //! [`Poll::Pending`]: https://doc.rust-lang.org/std/task/enum.Poll.html#variant.Pending
74 //! [`Context`]: https://doc.rust-lang.org/std/task/struct.Context.html
75 //! [`Waker`]: https://doc.rust-lang.org/std/task/struct.Waker.html
76 //! [`RawWaker`]: https://doc.rust-lang.org/std/task/struct.RawWaker.html
77 
78 use std::{
79     future::Future,
80     marker::PhantomData,
81     ops::Deref,
82     panic,
83     pin::Pin,
84     sync::{Arc, Mutex},
85     task::{Context, Poll, Wake},
86 };
87 
88 use super::{RustFutureContinuationCallback, RustFuturePoll, Scheduler};
89 use crate::{rust_call_with_out_status, FfiDefault, LowerReturn, RustCallStatus};
90 
91 /// Wraps the actual future we're polling
92 struct WrappedFuture<F, T, UT>
93 where
94     // See rust_future_new for an explanation of these trait bounds
95     F: Future<Output = T> + Send + 'static,
96     T: LowerReturn<UT> + Send + 'static,
97     UT: Send + 'static,
98 {
99     // Note: this could be a single enum, but that would make it easy to mess up the future pinning
100     // guarantee.   For example you might want to call `std::mem::take()` to try to get the result,
101     // but if the future happened to be stored that would move and break all internal references.
102     future: Option<F>,
103     result: Option<Result<T::ReturnType, RustCallStatus>>,
104 }
105 
106 impl<F, T, UT> WrappedFuture<F, T, UT>
107 where
108     // See rust_future_new for an explanation of these trait bounds
109     F: Future<Output = T> + Send + 'static,
110     T: LowerReturn<UT> + Send + 'static,
111     UT: Send + 'static,
112 {
new(future: F) -> Self113     fn new(future: F) -> Self {
114         Self {
115             future: Some(future),
116             result: None,
117         }
118     }
119 
120     // Poll the future and check if it's ready or not
poll(&mut self, context: &mut Context<'_>) -> bool121     fn poll(&mut self, context: &mut Context<'_>) -> bool {
122         if self.result.is_some() {
123             true
124         } else if let Some(future) = &mut self.future {
125             // SAFETY: We can call Pin::new_unchecked because:
126             //    - This is the only time we get a &mut to `self.future`
127             //    - We never poll the future after it's moved (for example by using take())
128             //    - We never move RustFuture, which contains us.
129             //    - RustFuture is private to this module so no other code can move it.
130             let pinned = unsafe { Pin::new_unchecked(future) };
131             // Run the poll and lift the result if it's ready
132             let mut out_status = RustCallStatus::default();
133             let result: Option<Poll<T::ReturnType>> = rust_call_with_out_status(
134                 &mut out_status,
135                 // This closure uses a `&mut F` value, which means it's not UnwindSafe by
136                 // default.  If the future panics, it may be in an invalid state.
137                 //
138                 // However, we can safely use `AssertUnwindSafe` since a panic will lead the `None`
139                 // case below and we will never poll the future again.
140                 panic::AssertUnwindSafe(|| match pinned.poll(context) {
141                     Poll::Pending => Ok(Poll::Pending),
142                     Poll::Ready(v) => T::lower_return(v).map(Poll::Ready),
143                 }),
144             );
145             match result {
146                 Some(Poll::Pending) => false,
147                 Some(Poll::Ready(v)) => {
148                     self.future = None;
149                     self.result = Some(Ok(v));
150                     true
151                 }
152                 None => {
153                     self.future = None;
154                     self.result = Some(Err(out_status));
155                     true
156                 }
157             }
158         } else {
159             log::error!("poll with neither future nor result set");
160             true
161         }
162     }
163 
complete(&mut self, out_status: &mut RustCallStatus) -> T::ReturnType164     fn complete(&mut self, out_status: &mut RustCallStatus) -> T::ReturnType {
165         let mut return_value = T::ReturnType::ffi_default();
166         match self.result.take() {
167             Some(Ok(v)) => return_value = v,
168             Some(Err(call_status)) => *out_status = call_status,
169             None => *out_status = RustCallStatus::cancelled(),
170         }
171         self.free();
172         return_value
173     }
174 
free(&mut self)175     fn free(&mut self) {
176         self.future = None;
177         self.result = None;
178     }
179 }
180 
181 // If F and T are Send, then WrappedFuture is too
182 //
183 // Rust will not mark it Send by default when T::ReturnType is a raw pointer.  This is promising
184 // that we will treat the raw pointer properly, for example by not returning it twice.
185 unsafe impl<F, T, UT> Send for WrappedFuture<F, T, UT>
186 where
187     // See rust_future_new for an explanation of these trait bounds
188     F: Future<Output = T> + Send + 'static,
189     T: LowerReturn<UT> + Send + 'static,
190     UT: Send + 'static,
191 {
192 }
193 
194 /// Future that the foreign code is awaiting
195 pub(super) struct RustFuture<F, T, UT>
196 where
197     // See rust_future_new for an explanation of these trait bounds
198     F: Future<Output = T> + Send + 'static,
199     T: LowerReturn<UT> + Send + 'static,
200     UT: Send + 'static,
201 {
202     // This Mutex should never block if our code is working correctly, since there should not be
203     // multiple threads calling [Self::poll] and/or [Self::complete] at the same time.
204     future: Mutex<WrappedFuture<F, T, UT>>,
205     scheduler: Mutex<Scheduler>,
206     // UT is used as the generic parameter for [LowerReturn].
207     // Let's model this with PhantomData as a function that inputs a UT value.
208     _phantom: PhantomData<fn(UT) -> ()>,
209 }
210 
211 impl<F, T, UT> RustFuture<F, T, UT>
212 where
213     // See rust_future_new for an explanation of these trait bounds
214     F: Future<Output = T> + Send + 'static,
215     T: LowerReturn<UT> + Send + 'static,
216     UT: Send + 'static,
217 {
new(future: F, _tag: UT) -> Arc<Self>218     pub(super) fn new(future: F, _tag: UT) -> Arc<Self> {
219         Arc::new(Self {
220             future: Mutex::new(WrappedFuture::new(future)),
221             scheduler: Mutex::new(Scheduler::new()),
222             _phantom: PhantomData,
223         })
224     }
225 
poll(self: Arc<Self>, callback: RustFutureContinuationCallback, data: u64)226     pub(super) fn poll(self: Arc<Self>, callback: RustFutureContinuationCallback, data: u64) {
227         let ready = self.is_cancelled() || {
228             let mut locked = self.future.lock().unwrap();
229             let waker: std::task::Waker = Arc::clone(&self).into();
230             locked.poll(&mut Context::from_waker(&waker))
231         };
232         if ready {
233             callback(data, RustFuturePoll::Ready)
234         } else {
235             self.scheduler.lock().unwrap().store(callback, data);
236         }
237     }
238 
is_cancelled(&self) -> bool239     pub(super) fn is_cancelled(&self) -> bool {
240         self.scheduler.lock().unwrap().is_cancelled()
241     }
242 
wake(&self)243     pub(super) fn wake(&self) {
244         self.scheduler.lock().unwrap().wake();
245     }
246 
cancel(&self)247     pub(super) fn cancel(&self) {
248         self.scheduler.lock().unwrap().cancel();
249     }
250 
complete(&self, call_status: &mut RustCallStatus) -> T::ReturnType251     pub(super) fn complete(&self, call_status: &mut RustCallStatus) -> T::ReturnType {
252         self.future.lock().unwrap().complete(call_status)
253     }
254 
free(self: Arc<Self>)255     pub(super) fn free(self: Arc<Self>) {
256         // Call cancel() to send any leftover data to the continuation callback
257         self.scheduler.lock().unwrap().cancel();
258         // Ensure we drop our inner future, releasing all held references
259         self.future.lock().unwrap().free();
260     }
261 }
262 
263 impl<F, T, UT> Wake for RustFuture<F, T, UT>
264 where
265     // See rust_future_new for an explanation of these trait bounds
266     F: Future<Output = T> + Send + 'static,
267     T: LowerReturn<UT> + Send + 'static,
268     UT: Send + 'static,
269 {
wake(self: Arc<Self>)270     fn wake(self: Arc<Self>) {
271         self.deref().wake()
272     }
273 
wake_by_ref(self: &Arc<Self>)274     fn wake_by_ref(self: &Arc<Self>) {
275         self.deref().wake()
276     }
277 }
278 
279 /// RustFuture FFI trait.  This allows `Arc<RustFuture<F, T, UT>>` to be cast to
280 /// `Arc<dyn RustFutureFfi<T::ReturnType>>`, which is needed to implement the public FFI API.  In particular, this
281 /// allows you to use RustFuture functionality without knowing the concrete Future type, which is
282 /// unnamable.
283 ///
284 /// This is parametrized on the ReturnType rather than the `T` directly, to reduce the number of
285 /// scaffolding functions we need to generate.  If it was parametrized on `T`, then we would need
286 /// to create a poll, cancel, complete, and free scaffolding function for each exported async
287 /// function.  That would add ~1kb binary size per exported function based on a quick estimate on a
288 /// x86-64 machine . By parametrizing on `T::ReturnType` we can instead monomorphize by hand and
289 /// only create those functions for each of the 13 possible FFI return types.
290 #[doc(hidden)]
291 pub trait RustFutureFfi<ReturnType>: Send + Sync {
ffi_poll(self: Arc<Self>, callback: RustFutureContinuationCallback, data: u64)292     fn ffi_poll(self: Arc<Self>, callback: RustFutureContinuationCallback, data: u64);
ffi_cancel(&self)293     fn ffi_cancel(&self);
ffi_complete(&self, call_status: &mut RustCallStatus) -> ReturnType294     fn ffi_complete(&self, call_status: &mut RustCallStatus) -> ReturnType;
ffi_free(self: Arc<Self>)295     fn ffi_free(self: Arc<Self>);
296 }
297 
298 impl<F, T, UT> RustFutureFfi<T::ReturnType> for RustFuture<F, T, UT>
299 where
300     // See rust_future_new for an explanation of these trait bounds
301     F: Future<Output = T> + Send + 'static,
302     T: LowerReturn<UT> + Send + 'static,
303     UT: Send + 'static,
304 {
ffi_poll(self: Arc<Self>, callback: RustFutureContinuationCallback, data: u64)305     fn ffi_poll(self: Arc<Self>, callback: RustFutureContinuationCallback, data: u64) {
306         self.poll(callback, data)
307     }
308 
ffi_cancel(&self)309     fn ffi_cancel(&self) {
310         self.cancel()
311     }
312 
ffi_complete(&self, call_status: &mut RustCallStatus) -> T::ReturnType313     fn ffi_complete(&self, call_status: &mut RustCallStatus) -> T::ReturnType {
314         self.complete(call_status)
315     }
316 
ffi_free(self: Arc<Self>)317     fn ffi_free(self: Arc<Self>) {
318         self.free();
319     }
320 }
321