at main 3.1 kB view raw
1use std::{array, cell::Cell, marker::PhantomPinned, pin::Pin, ptr::NonNull}; 2 3use futures_compat::{LocalWaker, WakePtr}; 4use futures_core::Wake; 5use lifetime_guard::{guard::RefGuard, guard::ValueGuard}; 6 7pub struct WakeArray<const N: usize> { 8 parent: RefGuard<WakePtr>, 9 children: [ValueGuard<WakePtr>; N], 10 stores: [WakeStore; N], 11 _marker: PhantomPinned, 12} 13 14impl<const N: usize> WakeArray<N> { 15 pub fn new() -> Self { 16 Self { 17 parent: RefGuard::new(), 18 children: array::from_fn(|_| ValueGuard::new(None)), 19 stores: array::from_fn(|_| WakeStore::new()), 20 _marker: PhantomPinned, 21 } 22 } 23 24 pub fn register_parent( 25 self: Pin<&Self>, 26 parent: Pin<&ValueGuard<WakePtr>>, 27 ) { 28 unsafe { Pin::new_unchecked(&self.parent) }.register(parent); 29 } 30 31 /// Returns pinned reference to child ValueGuard 32 /// returns None if n is not in 0..N 33 pub fn child_guard_ptr( 34 self: Pin<&Self>, 35 index: usize, 36 ) -> Option<Pin<&ValueGuard<WakePtr>>> { 37 // TODO remove bounds checking, break api when https://github.com/rust-lang/rust/issues/123646 38 if index >= N { 39 return None; 40 } 41 42 let wake_store = unsafe { self.stores.get(index).unwrap_unchecked() }; 43 wake_store.set_parent(&self.parent); 44 45 let wake_store = unsafe { 46 NonNull::new_unchecked( 47 wake_store as *const dyn Wake as *mut dyn Wake, 48 ) 49 }; 50 51 let child_guard = 52 unsafe { self.get_ref().children.get(index).unwrap_unchecked() }; 53 child_guard.set(Some(wake_store)); 54 55 Some(unsafe { Pin::new_unchecked(child_guard) }) 56 } 57 58 pub fn take_woken(self: Pin<&Self>, index: usize) -> Option<bool> { 59 self.stores.get(index).map(|store| store.take_woken()) 60 } 61} 62 63pub struct WakeStore { 64 wake_parent: Cell<Option<NonNull<RefGuard<WakePtr>>>>, 65 activated: Cell<bool>, 66} 67 68impl WakeStore { 69 pub fn new() -> Self { 70 Self { 71 wake_parent: Cell::new(None), 72 activated: Cell::new(true), 73 } 74 } 75 76 pub fn set_parent(&self, parent: &RefGuard<WakePtr>) { 77 self.wake_parent.set(Some(parent.into())); 78 } 79 80 pub fn take_woken(&self) -> bool { 81 self.activated.replace(false) 82 } 83} 84 85impl Wake for WakeStore { 86 fn wake(&self) { 87 dbg!("awake?"); 88 self.activated.set(true); 89 if let Some(parent) = self 90 .wake_parent 91 .get() 92 .map(|guard_ptr| unsafe { &*guard_ptr.as_ptr() }) 93 .and_then(|guard| guard.get()) 94 .flatten() 95 { 96 unsafe { &*parent.as_ptr() }.wake(); 97 } 98 } 99} 100 101pub fn local_wake(guard: &LocalWaker) { 102 if let Some(wake) = guard.get() { 103 unsafe { (*wake.as_ptr()).wake() } 104 } 105} 106 107// pub unsafe fn wake_bespoke_waker(waker: &std::task::Waker) { 108// unsafe { 109// let guard = futures_compat::waker_to_guard(waker); 110// if let Some(wake) = guard.get() { 111// (*wake.as_ptr()).wake(); 112// } 113// } 114// }