Skip to content

Commit de3d65e

Browse files
yukibtcbendk
authored andcommitted
core: reduce monomorphization of the futures
These changes will reduce the monomorphization of the futures, resulting in a reduction of the binary size. Signed-off-by: Yuki Kishimoto <[email protected]>
1 parent e6085aa commit de3d65e

File tree

3 files changed

+19
-29
lines changed

3 files changed

+19
-29
lines changed

uniffi_core/src/ffi/rustfuture/future.rs

+14-25
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
//! [`RawWaker`]: https://doc.rust-lang.org/std/task/struct.RawWaker.html
7777
7878
use std::{
79+
future::Future,
7980
marker::PhantomData,
8081
ops::Deref,
8182
panic,
@@ -87,29 +88,27 @@ use std::{
8788
use super::{RustFutureContinuationCallback, RustFuturePoll, Scheduler, UniffiCompatibleFuture};
8889
use crate::{rust_call_with_out_status, FfiDefault, LiftArgsError, LowerReturn, RustCallStatus};
8990

91+
type BoxedFuture<T> = Pin<Box<dyn UniffiCompatibleFuture<Result<T, LiftArgsError>>>>;
92+
9093
/// Wraps the actual future we're polling
91-
struct WrappedFuture<F, T, UT>
94+
struct WrappedFuture<T, UT>
9295
where
93-
// See rust_future_new for an explanation of these trait bounds
94-
F: UniffiCompatibleFuture<Result<T, LiftArgsError>> + 'static,
9596
T: LowerReturn<UT> + Send + 'static,
9697
UT: Send + 'static,
9798
{
9899
// Note: this could be a single enum, but that would make it easy to mess up the future pinning
99100
// guarantee. For example you might want to call `std::mem::take()` to try to get the result,
100101
// but if the future happened to be stored that would move and break all internal references.
101-
future: Option<F>,
102+
future: Option<BoxedFuture<T>>,
102103
result: Option<Result<T::ReturnType, RustCallStatus>>,
103104
}
104105

105-
impl<F, T, UT> WrappedFuture<F, T, UT>
106+
impl<T, UT> WrappedFuture<T, UT>
106107
where
107-
// See rust_future_new for an explanation of these trait bounds
108-
F: UniffiCompatibleFuture<Result<T, LiftArgsError>> + 'static,
109108
T: LowerReturn<UT> + Send + 'static,
110109
UT: Send + 'static,
111110
{
112-
fn new(future: F) -> Self {
111+
fn new(future: BoxedFuture<T>) -> Self {
113112
Self {
114113
future: Some(future),
115114
result: None,
@@ -182,40 +181,34 @@ where
182181
//
183182
// Rust will not mark it Send by default when T::ReturnType is a raw pointer. This is promising
184183
// 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>
184+
unsafe impl<T, UT> Send for WrappedFuture<T, UT>
186185
where
187-
// See rust_future_new for an explanation of these trait bounds
188-
F: UniffiCompatibleFuture<Result<T, LiftArgsError>> + 'static,
189186
T: LowerReturn<UT> + Send + 'static,
190187
UT: Send + 'static,
191188
{
192189
}
193190

194191
/// Future that the foreign code is awaiting
195-
pub(super) struct RustFuture<F, T, UT>
192+
pub(super) struct RustFuture<T, UT>
196193
where
197-
// See rust_future_new for an explanation of these trait bounds
198-
F: UniffiCompatibleFuture<Result<T, LiftArgsError>> + 'static,
199194
T: LowerReturn<UT> + Send + 'static,
200195
UT: Send + 'static,
201196
{
202197
// This Mutex should never block if our code is working correctly, since there should not be
203198
// multiple threads calling [Self::poll] and/or [Self::complete] at the same time.
204-
future: Mutex<WrappedFuture<F, T, UT>>,
199+
future: Mutex<WrappedFuture<T, UT>>,
205200
scheduler: Mutex<Scheduler>,
206201
// UT is used as the generic parameter for [LowerReturn].
207202
// Let's model this with PhantomData as a function that inputs a UT value.
208203
_phantom: PhantomData<fn(UT) -> ()>,
209204
}
210205

211-
impl<F, T, UT> RustFuture<F, T, UT>
206+
impl<T, UT> RustFuture<T, UT>
212207
where
213-
// See rust_future_new for an explanation of these trait bounds
214-
F: UniffiCompatibleFuture<Result<T, LiftArgsError>> + 'static,
215208
T: LowerReturn<UT> + Send + 'static,
216209
UT: Send + 'static,
217210
{
218-
pub(super) fn new(future: F, _tag: UT) -> Arc<Self> {
211+
pub(super) fn new(future: BoxedFuture<T>, _tag: UT) -> Arc<Self> {
219212
Arc::new(Self {
220213
future: Mutex::new(WrappedFuture::new(future)),
221214
scheduler: Mutex::new(Scheduler::new()),
@@ -263,10 +256,8 @@ where
263256
}
264257
}
265258

266-
impl<F, T, UT> Wake for RustFuture<F, T, UT>
259+
impl<T, UT> Wake for RustFuture<T, UT>
267260
where
268-
// See rust_future_new for an explanation of these trait bounds
269-
F: UniffiCompatibleFuture<Result<T, LiftArgsError>> + 'static,
270261
T: LowerReturn<UT> + Send + 'static,
271262
UT: Send + 'static,
272263
{
@@ -298,10 +289,8 @@ pub trait RustFutureFfi<ReturnType>: Send + Sync {
298289
fn ffi_free(self: Arc<Self>);
299290
}
300291

301-
impl<F, T, UT> RustFutureFfi<T::ReturnType> for RustFuture<F, T, UT>
292+
impl<T, UT> RustFutureFfi<T::ReturnType> for RustFuture<T, UT>
302293
where
303-
// See rust_future_new for an explanation of these trait bounds
304-
F: UniffiCompatibleFuture<Result<T, LiftArgsError>> + 'static,
305294
T: LowerReturn<UT> + Send + 'static,
306295
UT: Send + 'static,
307296
{

uniffi_core/src/ffi/rustfuture/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,8 @@ where
109109
// Needed to allocate a handle
110110
dyn RustFutureFfi<T::ReturnType>: HandleAlloc<UT>,
111111
{
112-
let handle = <dyn RustFutureFfi<T::ReturnType> as HandleAlloc<UT>>::new_handle(
113-
RustFuture::new(future, tag) as Arc<dyn RustFutureFfi<T::ReturnType>>,
112+
let handle = HandleAlloc::new_handle(
113+
RustFuture::new(Box::pin(future), tag) as Arc<dyn RustFutureFfi<T::ReturnType>>
114114
);
115115
trace!("rust_future_new: {handle:?}");
116116
handle

uniffi_core/src/ffi/rustfuture/tests.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ fn channel() -> (Sender, Arc<dyn RustFutureFfi<RustBuffer>>) {
7878
result: None,
7979
waker: None,
8080
}));
81-
let rust_future = RustFuture::new(Receiver(channel.clone()), crate::UniFfiTag);
81+
let rust_future = RustFuture::new(Box::pin(Receiver(channel.clone())), crate::UniFfiTag);
8282
(Sender(channel), rust_future)
8383
}
8484

@@ -246,7 +246,8 @@ fn test_wake_during_poll() {
246246
Poll::Ready(Ok("All done".to_owned()))
247247
}
248248
});
249-
let rust_future: Arc<dyn RustFutureFfi<RustBuffer>> = RustFuture::new(future, crate::UniFfiTag);
249+
let rust_future: Arc<dyn RustFutureFfi<RustBuffer>> =
250+
RustFuture::new(Box::pin(future), crate::UniFfiTag);
250251
let continuation_result = poll(&rust_future);
251252
// The continuation function should called immediately
252253
assert_eq!(continuation_result.get(), Some(&RustFuturePoll::MaybeReady));

0 commit comments

Comments
 (0)