wip
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// }