at main 4.1 kB view raw
1//! Any interaction between an executor/reactor intended for task::Future 2//! with an executor/reactor intended for bcsc::Future is strictly unsound. 3 4use std::{ 5 hint::unreachable_unchecked, 6 mem::ManuallyDrop, 7 pin::Pin, 8 ptr::NonNull, 9 task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, 10}; 11 12use futures_core::Wake; 13use lifetime_guard::{atomic_guard::AtomicValueGuard, guard::ValueGuard}; 14 15pub type WakePtr = Option<NonNull<dyn Wake>>; 16pub type LocalWaker = ValueGuard<WakePtr>; 17pub type AtomicWaker = AtomicValueGuard<WakePtr>; 18 19static EVIL_VTABLE: RawWakerVTable = unsafe { 20 RawWakerVTable::new( 21 |_| unreachable_unchecked(), 22 |_| unreachable_unchecked(), 23 |_| unreachable_unchecked(), 24 |_| unreachable_unchecked(), 25 ) 26}; 27 28/// Coerces a pinned `ValueGuard` reference to a `Waker` for use in 29/// `core::future::Future` 30/// 31/// Any usage or storage of the resulting `Waker` is undefined behavior. 32pub unsafe fn guard_to_waker(guard: Pin<&LocalWaker>) -> ManuallyDrop<Waker> { 33 ManuallyDrop::new(unsafe { 34 Waker::from_raw(RawWaker::new( 35 guard.get_ref() as *const ValueGuard<WakePtr> as *const (), 36 &EVIL_VTABLE, 37 )) 38 }) 39} 40 41pub unsafe fn atomic_guard_to_waker( 42 guard: Pin<&AtomicWaker>, 43) -> ManuallyDrop<Waker> { 44 ManuallyDrop::new(unsafe { 45 Waker::from_raw(RawWaker::new( 46 guard.get_ref() as *const AtomicValueGuard<WakePtr> as *const (), 47 &EVIL_VTABLE, 48 )) 49 }) 50} 51 52/// Coerces a `Waker` into a pinned `AtomicValueGuard` reference. 53/// 54/// This should only be used to undo the work of `guard_to_waker`. 55pub unsafe fn waker_to_guard<'a>(waker: &Waker) -> Pin<&LocalWaker> { 56 unsafe { 57 Pin::new_unchecked(&*(waker.data() as *const ValueGuard<WakePtr>)) 58 } 59} 60 61pub unsafe fn waker_to_atomic_guard<'a>(waker: &Waker) -> Pin<&AtomicWaker> { 62 unsafe { 63 Pin::new_unchecked(&*(waker.data() as *const AtomicValueGuard<WakePtr>)) 64 } 65} 66 67pub unsafe fn std_future_to_bespoke<F: core::future::Future>( 68 future: F, 69) -> impl futures_core::Future<LocalWaker, Output = F::Output> { 70 NormalFutureWrapper(future) 71} 72 73pub unsafe fn bespoke_future_to_std<F: futures_core::Future<LocalWaker>>( 74 future: F, 75) -> impl core::future::Future<Output = F::Output> { 76 BespokeFutureWrapper(future) 77} 78 79/// wraps `core::future::Future` in impl of `bcsc:Future` 80#[repr(transparent)] 81pub struct NormalFutureWrapper<F: core::future::Future>(F); 82 83impl<F: core::future::Future> futures_core::Future<LocalWaker> 84 for NormalFutureWrapper<F> 85{ 86 type Output = F::Output; 87 88 fn poll( 89 self: Pin<&mut Self>, 90 waker: Pin<&LocalWaker>, 91 ) -> Poll<Self::Output> { 92 unsafe { 93 self.map_unchecked_mut(|this| &mut this.0) 94 .poll(&mut Context::from_waker(&guard_to_waker(waker))) 95 } 96 } 97} 98 99/// wraps custom `bcsc::Future` in impl of `core::future::Future` 100#[repr(transparent)] 101pub struct BespokeFutureWrapper<F>(F) 102where 103 F: futures_core::Future<LocalWaker>; 104 105impl<F> core::future::Future for BespokeFutureWrapper<F> 106where 107 F: futures_core::Future<LocalWaker>, 108{ 109 type Output = F::Output; 110 111 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { 112 unsafe { 113 self.map_unchecked_mut(|this| &mut this.0) 114 .poll(waker_to_guard(cx.waker())) 115 } 116 } 117} 118 119#[cfg(test)] 120mod test { 121 use std::pin; 122 123 use super::*; 124 use futures_core::Wake; 125 126 #[derive(Debug)] 127 struct DummyWake; 128 impl Wake for DummyWake { 129 fn wake(&self) {} 130 } 131 132 #[test] 133 fn waker_conversion() { 134 let dummy = DummyWake; 135 let guard = pin::pin!(ValueGuard::new(NonNull::new( 136 &dummy as *const dyn Wake as *mut dyn Wake 137 ))); 138 let waker = unsafe { guard_to_waker(guard.as_ref()) }; 139 let guard = unsafe { waker_to_guard(&waker) }; 140 assert_eq!( 141 guard.get().unwrap().as_ptr() as *const () as usize, 142 &dummy as *const _ as *const () as usize 143 ); 144 } 145}