stabby_abi/
future.rs

1//
2// Copyright (c) 2023 ZettaScale Technology
3//
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7// which is available at https://www.apache.org/licenses/LICENSE-2.0.
8//
9// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10//
11// Contributors:
12//   Pierre Avital, <pierre.avital@me.com>
13//
14
15use core::task::Context;
16
17use crate::enums::IDeterminantProvider;
18use crate::option::Option;
19use crate::vtable::HasDropVt;
20use crate::{IPtrMut, IPtrOwned, IStable};
21
22pub use stable_waker::StableWaker;
23#[cfg(stabby_unsafe_wakers = "true")]
24mod stable_waker {
25    use core::task::Waker;
26
27    use crate::StableLike;
28    /// A waker that promises to be ABI stable.
29    ///
30    /// With the `stabby_unsafe_wakers` feature enabled, this is actually a lie: the waker is not guaranteed to
31    /// be ABI-stable! However, since building ABI-stable wakers that are compatible with Rust's wakers is
32    /// costly in terms of runtime, you might want to experiment with unsafe wakers, to bench the cost of
33    /// stable wakers if nothing else.
34    #[crate::stabby]
35    pub struct StableWaker<'a>(StableLike<&'a Waker, &'a ()>);
36    impl StableWaker<'_> {
37        /// Exposes `self` as a [`core::task::Waker`], letting you use it to run standard futures.
38        ///
39        /// You generally shouldn't need to do this manually.
40        pub fn with_waker<'a, F: FnOnce(&'a Waker) -> U, U>(&'a self, f: F) -> U {
41            f(unsafe { self.0.as_ref_unchecked() })
42        }
43    }
44    impl<'a> From<&'a Waker> for StableWaker<'a> {
45        fn from(value: &'a Waker) -> Self {
46            Self(StableLike::new(value))
47        }
48    }
49}
50#[cfg(any(not(stabby_unsafe_wakers), stabby_unsafe_wakers = "false"))]
51mod stable_waker {
52    use core::{
53        mem::ManuallyDrop,
54        ptr::NonNull,
55        task::{RawWaker, RawWakerVTable, Waker},
56    };
57
58    use crate::alloc::{sync::Arc, AllocPtr, IAlloc};
59    use crate::StableLike;
60
61    mod seal {
62        use super::*;
63        use crate::Tuple as Tuple2;
64        #[crate::stabby]
65        pub struct StableWakerInner {
66            pub waker: StableLike<ManuallyDrop<Waker>, Tuple2<*const (), &'static ()>>,
67            pub wake_by_ref: StableLike<for<'b> unsafe extern "C" fn(&'b Waker), &'static ()>,
68            pub drop: StableLike<unsafe extern "C" fn(&mut ManuallyDrop<Waker>), &'static ()>,
69        }
70        // SAFETY: this is a wrapper around Send and Sync Wakers
71        unsafe impl Send for StableWakerInner where core::task::Waker: Send {}
72        // SAFETY: this is a wrapper around Send and Sync Wakers
73        unsafe impl Sync for StableWakerInner where core::task::Waker: Sync {}
74        impl Drop for StableWakerInner {
75            fn drop(&mut self) {
76                unsafe { (self.drop.as_mut_unchecked())(self.waker.as_mut_unchecked()) }
77            }
78        }
79        #[crate::stabby]
80        pub struct SharedStableWaker<Alloc: IAlloc>(pub Arc<StableWakerInner, Alloc>);
81        impl<Alloc: IAlloc> SharedStableWaker<Alloc> {
82            unsafe fn clone(this: *const ()) -> RawWaker {
83                Arc::<_, Alloc>::increment_strong_count(this);
84                RawWaker::new(this, &Self::VTABLE)
85            }
86            unsafe fn drop(this: *const ()) {
87                let this = AllocPtr {
88                    ptr: NonNull::new(this as *mut _).unwrap(),
89                    marker: core::marker::PhantomData,
90                };
91                let this = Arc::from_raw(this);
92                Self(this);
93            }
94            unsafe fn wake(this: *const ()) {
95                Self::wake_by_ref(this);
96                Self::drop(this);
97            }
98            unsafe fn wake_by_ref(this: *const ()) {
99                let this = unsafe { &*(this as *const StableWakerInner) };
100                (this.wake_by_ref.as_ref_unchecked())(this.waker.as_ref_unchecked())
101            }
102            const VTABLE: RawWakerVTable =
103                RawWakerVTable::new(Self::clone, Self::wake, Self::wake_by_ref, Self::drop);
104            pub fn into_raw_waker(self) -> RawWaker {
105                RawWaker::new(
106                    Arc::into_raw(self.0).ptr.as_ptr() as *const _,
107                    &Self::VTABLE,
108                )
109            }
110        }
111    }
112    use seal::*;
113    /// An ABI-stable waker.
114    ///
115    /// This is done by wrapping a provided [`core::task::Waker`] with calling convention-shims.
116    ///
117    /// While this is the only way to guarantee ABI-stability when interacting with futures, this does add
118    /// a layer of indirection, and cloning this waker will cause an allocation. To bench the performance cost
119    /// of this wrapper and decide if you want to risk ABI-unstability on wakers, you may use `RUSTFLAGS='--cfg stabby_unsafe_wakers="true"'`, which will turn [`StableWaker`] into a newtype of [`core::task::Waker`].
120    #[crate::stabby]
121    pub struct StableWaker<'a, Alloc: IAlloc = crate::alloc::DefaultAllocator> {
122        waker: StableLike<&'a Waker, &'a ()>,
123        #[allow(improper_ctypes_definitions)]
124        clone: unsafe extern "C" fn(StableLike<&'a Waker, &'a ()>) -> SharedStableWaker<Alloc>,
125        wake_by_ref: StableLike<unsafe extern "C" fn(&Waker), &'a ()>,
126    }
127    impl<Alloc: IAlloc + Default> StableWaker<'_, Alloc> {
128        /// Turns this into a waker whose clone implementation is to clone the underlying waker into a stable Arc.
129        pub fn with_waker<F: FnOnce(&Waker) -> U, U>(&self, f: F) -> U {
130            const VTABLE: RawWakerVTable =
131                RawWakerVTable::new(clone, wake_by_ref, wake_by_ref, drop);
132            unsafe fn clone(this: *const ()) -> RawWaker {
133                let this = unsafe { &*(this as *const StableWaker) };
134                (this.clone)(this.waker).into_raw_waker()
135            }
136            unsafe fn wake_by_ref(this: *const ()) {
137                let this = unsafe { &*(this as *const StableWaker) };
138                (this.wake_by_ref.as_ref_unchecked())(this.waker.as_ref_unchecked())
139            }
140            const unsafe fn drop(_: *const ()) {}
141            let waker = RawWaker::new(self as *const Self as *const _, &VTABLE);
142            let waker = unsafe { Waker::from_raw(waker) };
143            f(&waker)
144        }
145        unsafe extern "C" fn waker_drop(waker: &mut ManuallyDrop<Waker>) {
146            ManuallyDrop::drop(waker)
147        }
148        unsafe extern "C" fn waker_wake_by_ref(waker: &Waker) {
149            waker.wake_by_ref()
150        }
151        unsafe extern "C" fn clone_borrowed(
152            borrowed_waker: StableLike<&Waker, &()>,
153        ) -> SharedStableWaker<Alloc> {
154            let borrowed_waker = *borrowed_waker.as_ref_unchecked();
155            let waker = borrowed_waker.clone();
156            let waker = StableWakerInner {
157                waker: StableLike::new(ManuallyDrop::new(waker)),
158                wake_by_ref: StableLike::new(Self::waker_wake_by_ref),
159                drop: StableLike::new(Self::waker_drop),
160            };
161            let shared = Arc::new_in(waker, Default::default());
162            SharedStableWaker(shared)
163        }
164    }
165    impl<'a, Alloc: IAlloc + Default> From<&'a Waker> for StableWaker<'a, Alloc> {
166        fn from(value: &'a Waker) -> Self {
167            StableWaker {
168                waker: StableLike::new(value),
169                clone: Self::clone_borrowed,
170                wake_by_ref: StableLike::new(Self::waker_wake_by_ref),
171            }
172        }
173    }
174}
175
176/// [`core::future::Future`], but ABI-stable.
177#[crate::stabby]
178pub trait Future {
179    /// The output type of the future.
180    type Output: IDeterminantProvider<()>;
181    /// Equivalent to [`core::future::Future::poll`].
182    extern "C" fn poll<'a>(&'a mut self, waker: StableWaker<'a>) -> Option<Self::Output>;
183}
184impl<T: core::future::Future> Future for T
185where
186    T::Output: IDeterminantProvider<()>,
187{
188    type Output = T::Output;
189    #[allow(improper_ctypes_definitions)]
190    extern "C" fn poll(&mut self, waker: StableWaker) -> Option<Self::Output> {
191        waker.with_waker(|waker| {
192            match core::future::Future::poll(
193                unsafe { core::pin::Pin::new_unchecked(self) },
194                &mut Context::from_waker(waker),
195            ) {
196                core::task::Poll::Ready(v) => Option::Some(v),
197                core::task::Poll::Pending => Option::None(),
198            }
199        })
200    }
201}
202
203impl<Vt: HasDropVt, P: IPtrOwned + IPtrMut, Output: IDeterminantProvider<()>> core::future::Future
204    for crate::Dyn<'_, P, crate::vtable::VTable<StabbyVtableFuture<'_, Output>, Vt>>
205{
206    type Output = Output;
207    fn poll(
208        self: core::pin::Pin<&mut Self>,
209        cx: &mut Context<'_>,
210    ) -> core::task::Poll<Self::Output> {
211        unsafe {
212            let this = core::pin::Pin::get_unchecked_mut(self);
213            (this.vtable().head.poll.as_ref_unchecked())(
214                this.ptr_mut().as_mut(),
215                core::marker::PhantomData,
216                cx.waker().into(),
217            )
218            .match_owned(|v| core::task::Poll::Ready(v), || core::task::Poll::Pending)
219        }
220    }
221}
222
223impl<Vt: HasDropVt, P: IPtrOwned + IPtrMut, Output: IDeterminantProvider<()>> core::future::Future
224    for crate::Dyn<
225        '_,
226        P,
227        crate::vtable::VtSend<crate::vtable::VTable<StabbyVtableFuture<'_, Output>, Vt>>,
228    >
229{
230    type Output = Output;
231    fn poll(
232        self: core::pin::Pin<&mut Self>,
233        cx: &mut Context<'_>,
234    ) -> core::task::Poll<Self::Output> {
235        unsafe {
236            let this = core::pin::Pin::get_unchecked_mut(self);
237            (this.vtable().0.head.poll.as_ref_unchecked())(
238                this.ptr_mut().as_mut(),
239                core::marker::PhantomData,
240                cx.waker().into(),
241            )
242            .match_owned(|v| core::task::Poll::Ready(v), || core::task::Poll::Pending)
243        }
244    }
245}
246
247impl<Vt: HasDropVt, P: IPtrOwned + IPtrMut, Output: IDeterminantProvider<()>> core::future::Future
248    for crate::Dyn<
249        '_,
250        P,
251        crate::vtable::VtSync<crate::vtable::VTable<StabbyVtableFuture<'_, Output>, Vt>>,
252    >
253{
254    type Output = Output;
255    fn poll(
256        self: core::pin::Pin<&mut Self>,
257        cx: &mut Context<'_>,
258    ) -> core::task::Poll<Self::Output> {
259        unsafe {
260            let this = core::pin::Pin::get_unchecked_mut(self);
261            (this.vtable().0.head.poll.as_ref_unchecked())(
262                this.ptr_mut().as_mut(),
263                core::marker::PhantomData,
264                cx.waker().into(),
265            )
266            .match_owned(|v| core::task::Poll::Ready(v), || core::task::Poll::Pending)
267        }
268    }
269}
270
271impl<Vt: HasDropVt, P: IPtrOwned + IPtrMut, Output: IDeterminantProvider<()>> core::future::Future
272    for crate::Dyn<
273        '_,
274        P,
275        crate::vtable::VtSync<
276            crate::vtable::VtSend<crate::vtable::VTable<StabbyVtableFuture<'_, Output>, Vt>>,
277        >,
278    >
279{
280    type Output = Output;
281    fn poll(
282        self: core::pin::Pin<&mut Self>,
283        cx: &mut Context<'_>,
284    ) -> core::task::Poll<Self::Output> {
285        unsafe {
286            let this = core::pin::Pin::get_unchecked_mut(self);
287            (this.vtable().0 .0.head.poll.as_ref_unchecked())(
288                this.ptr_mut().as_mut(),
289                core::marker::PhantomData,
290                cx.waker().into(),
291            )
292            .match_owned(|v| core::task::Poll::Ready(v), || core::task::Poll::Pending)
293        }
294    }
295}
296
297impl<Vt: HasDropVt, P: IPtrOwned + IPtrMut, Output: IDeterminantProvider<()>> core::future::Future
298    for crate::Dyn<
299        '_,
300        P,
301        crate::vtable::VtSend<
302            crate::vtable::VtSync<crate::vtable::VTable<StabbyVtableFuture<'_, Output>, Vt>>,
303        >,
304    >
305{
306    type Output = Output;
307    fn poll(
308        self: core::pin::Pin<&mut Self>,
309        cx: &mut Context<'_>,
310    ) -> core::task::Poll<Self::Output> {
311        unsafe {
312            let this = core::pin::Pin::get_unchecked_mut(self);
313            (this.vtable().0 .0.head.poll.as_ref_unchecked())(
314                this.ptr_mut().as_mut(),
315                core::marker::PhantomData,
316                cx.waker().into(),
317            )
318            .match_owned(|v| core::task::Poll::Ready(v), || core::task::Poll::Pending)
319        }
320    }
321}
322
323impl<'a, Output> crate::vtable::CompoundVt<'a> for dyn core::future::Future<Output = Output>
324where
325    dyn Future<Output = Output>: crate::vtable::CompoundVt<'a>,
326{
327    type Vt<T> = <dyn Future<Output = Output> as crate::vtable::CompoundVt<'a>>::Vt<T>;
328}
329
330/// A future that may have already been resolved from the moment it was constructed.
331#[crate::stabby]
332pub enum MaybeResolved<T, F>
333where
334    F: core::future::Future<Output = T>,
335{
336    /// The future was resolved from its construction.
337    Resolved(T),
338    /// The future has been consumed already.
339    Empty,
340    /// The future is yet to be resolved.
341    Pending(F),
342}
343impl<T: IStable + Unpin, F: IStable + core::future::Future<Output = T> + Unpin> core::future::Future
344    for MaybeResolved<T, F>
345where
346    F: crate::IStable,
347    crate::Result<(), F>: crate::IStable,
348    T: crate::IDeterminantProvider<crate::Result<(), F>>,
349    (): crate::IDeterminantProvider<F>,
350{
351    type Output = T;
352    fn poll(
353        self: core::pin::Pin<&mut Self>,
354        cx: &mut Context<'_>,
355    ) -> core::task::Poll<Self::Output> {
356        let this = self.get_mut();
357        let inner = this as *mut _;
358        this.match_mut(
359            |value| {
360                let value = unsafe {
361                    let value = core::ptr::read(value);
362                    core::ptr::write(inner, MaybeResolved::Empty());
363                    value
364                };
365                core::task::Poll::Ready(value)
366            },
367            || core::task::Poll::Pending,
368            |future| match core::future::Future::poll(core::pin::Pin::new(future), cx) {
369                core::task::Poll::Ready(value) => {
370                    unsafe {
371                        core::ptr::replace(inner, MaybeResolved::Empty());
372                    }
373                    core::task::Poll::Ready(value)
374                }
375                core::task::Poll::Pending => core::task::Poll::Pending,
376            },
377        )
378    }
379}