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 use std::{future::Future, sync::Arc};
6
7 mod future;
8 mod scheduler;
9 use future::*;
10 use scheduler::*;
11
12 #[cfg(test)]
13 mod tests;
14
15 use crate::{derive_ffi_traits, Handle, HandleAlloc, LowerReturn, RustCallStatus};
16
17 /// Result code for [rust_future_poll]. This is passed to the continuation function.
18 #[repr(i8)]
19 #[derive(Debug, PartialEq, Eq)]
20 pub enum RustFuturePoll {
21 /// The future is ready and is waiting for [rust_future_complete] to be called
22 Ready = 0,
23 /// The future might be ready and [rust_future_poll] should be called again
24 MaybeReady = 1,
25 }
26
27 /// Foreign callback that's passed to [rust_future_poll]
28 ///
29 /// The Rust side of things calls this when the foreign side should call [rust_future_poll] again
30 /// to continue progress on the future.
31 pub type RustFutureContinuationCallback = extern "C" fn(callback_data: u64, RustFuturePoll);
32
33 // === Public FFI API ===
34
35 /// Create a new [Handle] for a Rust future
36 ///
37 /// For each exported async function, UniFFI will create a scaffolding function that uses this to
38 /// create the [Handle] to pass to the foreign code.
rust_future_new<F, T, UT>(future: F, tag: UT) -> Handle where F: Future<Output = T> + Send + 'static, T: LowerReturn<UT> + Send + 'static, UT: Send + 'static, dyn RustFutureFfi<T::ReturnType>: HandleAlloc<UT>,39 pub fn rust_future_new<F, T, UT>(future: F, tag: UT) -> Handle
40 where
41 // F is the future type returned by the exported async function. It needs to be Send + `static
42 // since it will move between threads for an indeterminate amount of time as the foreign
43 // executor calls polls it and the Rust executor wakes it. It does not need to by `Sync`,
44 // since we synchronize all access to the values.
45 F: Future<Output = T> + Send + 'static,
46 // T is the output of the Future. It needs to implement [LowerReturn]. Also it must be Send +
47 // 'static for the same reason as F.
48 T: LowerReturn<UT> + Send + 'static,
49 // The UniFfiTag ZST. The Send + 'static bound is to keep rustc happy.
50 UT: Send + 'static,
51 // Needed to allocate a handle
52 dyn RustFutureFfi<T::ReturnType>: HandleAlloc<UT>,
53 {
54 <dyn RustFutureFfi<T::ReturnType> as HandleAlloc<UT>>::new_handle(
55 RustFuture::new(future, tag) as Arc<dyn RustFutureFfi<T::ReturnType>>
56 )
57 }
58
59 /// Poll a Rust future
60 ///
61 /// When the future is ready to progress the continuation will be called with the `data` value and
62 /// a [RustFuturePoll] value. For each [rust_future_poll] call the continuation will be called
63 /// exactly once.
64 ///
65 /// # Safety
66 ///
67 /// The [Handle] must not previously have been passed to [rust_future_free]
rust_future_poll<ReturnType, UT>( handle: Handle, callback: RustFutureContinuationCallback, data: u64, ) where dyn RustFutureFfi<ReturnType>: HandleAlloc<UT>,68 pub unsafe fn rust_future_poll<ReturnType, UT>(
69 handle: Handle,
70 callback: RustFutureContinuationCallback,
71 data: u64,
72 ) where
73 dyn RustFutureFfi<ReturnType>: HandleAlloc<UT>,
74 {
75 <dyn RustFutureFfi<ReturnType> as HandleAlloc<UT>>::get_arc(handle).ffi_poll(callback, data)
76 }
77
78 /// Cancel a Rust future
79 ///
80 /// Any current and future continuations will be immediately called with RustFuturePoll::Ready.
81 ///
82 /// This is needed for languages like Swift, which continuation to wait for the continuation to be
83 /// called when tasks are cancelled.
84 ///
85 /// # Safety
86 ///
87 /// The [Handle] must not previously have been passed to [rust_future_free]
rust_future_cancel<ReturnType, UT>(handle: Handle) where dyn RustFutureFfi<ReturnType>: HandleAlloc<UT>,88 pub unsafe fn rust_future_cancel<ReturnType, UT>(handle: Handle)
89 where
90 dyn RustFutureFfi<ReturnType>: HandleAlloc<UT>,
91 {
92 <dyn RustFutureFfi<ReturnType> as HandleAlloc<UT>>::get_arc(handle).ffi_cancel()
93 }
94
95 /// Complete a Rust future
96 ///
97 /// Note: the actually extern "C" scaffolding functions can't be generic, so we generate one for
98 /// each supported FFI type.
99 ///
100 /// # Safety
101 ///
102 /// - The [Handle] must not previously have been passed to [rust_future_free]
103 /// - The `T` param must correctly correspond to the [rust_future_new] call. It must
104 /// be `<Output as LowerReturn<UT>>::ReturnType`
rust_future_complete<ReturnType, UT>( handle: Handle, out_status: &mut RustCallStatus, ) -> ReturnType where dyn RustFutureFfi<ReturnType>: HandleAlloc<UT>,105 pub unsafe fn rust_future_complete<ReturnType, UT>(
106 handle: Handle,
107 out_status: &mut RustCallStatus,
108 ) -> ReturnType
109 where
110 dyn RustFutureFfi<ReturnType>: HandleAlloc<UT>,
111 {
112 <dyn RustFutureFfi<ReturnType> as HandleAlloc<UT>>::get_arc(handle).ffi_complete(out_status)
113 }
114
115 /// Free a Rust future, dropping the strong reference and releasing all references held by the
116 /// future.
117 ///
118 /// # Safety
119 ///
120 /// The [Handle] must not previously have been passed to [rust_future_free]
rust_future_free<ReturnType, UT>(handle: Handle) where dyn RustFutureFfi<ReturnType>: HandleAlloc<UT>,121 pub unsafe fn rust_future_free<ReturnType, UT>(handle: Handle)
122 where
123 dyn RustFutureFfi<ReturnType>: HandleAlloc<UT>,
124 {
125 <dyn RustFutureFfi<ReturnType> as HandleAlloc<UT>>::consume_handle(handle).ffi_free()
126 }
127
128 // Derive HandleAlloc for dyn RustFutureFfi<T> for all FFI return types
129 derive_ffi_traits!(impl<UT> HandleAlloc<UT> for dyn RustFutureFfi<u8>);
130 derive_ffi_traits!(impl<UT> HandleAlloc<UT> for dyn RustFutureFfi<i8>);
131 derive_ffi_traits!(impl<UT> HandleAlloc<UT> for dyn RustFutureFfi<u16>);
132 derive_ffi_traits!(impl<UT> HandleAlloc<UT> for dyn RustFutureFfi<i16>);
133 derive_ffi_traits!(impl<UT> HandleAlloc<UT> for dyn RustFutureFfi<u32>);
134 derive_ffi_traits!(impl<UT> HandleAlloc<UT> for dyn RustFutureFfi<i32>);
135 derive_ffi_traits!(impl<UT> HandleAlloc<UT> for dyn RustFutureFfi<u64>);
136 derive_ffi_traits!(impl<UT> HandleAlloc<UT> for dyn RustFutureFfi<i64>);
137 derive_ffi_traits!(impl<UT> HandleAlloc<UT> for dyn RustFutureFfi<f32>);
138 derive_ffi_traits!(impl<UT> HandleAlloc<UT> for dyn RustFutureFfi<f64>);
139 derive_ffi_traits!(impl<UT> HandleAlloc<UT> for dyn RustFutureFfi<*const std::ffi::c_void>);
140 derive_ffi_traits!(impl<UT> HandleAlloc<UT> for dyn RustFutureFfi<crate::RustBuffer>);
141 derive_ffi_traits!(impl<UT> HandleAlloc<UT> for dyn RustFutureFfi<()>);
142