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