waker_waiter/
lib.rs

1//! This library helps async runtimes support the execution of arbitrary futures, by enabling futures to provide their own event polling logic. It is an attempt to implement the approach described by [Context reactor hook](https://jblog.andbit.net/2022/12/28/context-reactor-hook/).
2//!
3//! There are two integration points:
4//! - Futures that need to run their own event polling logic in the execution thread must call [`get_poller`] to obtain a [`TopLevelPoller`] and then call [`TopLevelPoller::set_waiter`] to register a [`WakerWaiter`] on it.
5//! - Whatever part of the application that is responsible for polling top-level futures (i.e. the async runtime) needs to implement the [`TopLevelPoller`] trait and provide it using [`std::task::ContextBuilder::ext`]. This library provides such an implementation via [`block_on`].
6//!
7//! Only one [`WakerWaiter`] can be registered on a [`TopLevelPoller`]. If more than one future relies on the same event polling logic, the futures should coordinate and share the same [`WakerWaiter`].
8//!
9//!
10//! # Example of a future registering a `WakerWaiter`
11//!
12//! ```
13//! # use std::future::Future;
14//! # use std::pin::Pin;
15//! # use std::sync::{Arc, Mutex, Weak};
16//! # use std::task::{Context, Poll};
17//! # use waker_waiter::{TopLevelPoller, WakerWait, WakerWaiter, WakerWaiterCanceler, get_poller};
18//! #
19//! static REACTOR: Mutex<Option<Arc<Reactor>>> = Mutex::new(None);
20//!
21//! struct Reactor {
22//!     waiter: Option<WakerWaiter>,
23//! }
24//!
25//! impl Reactor {
26//!     fn current() -> Arc<Reactor> {
27//!         let mut reactor = REACTOR.lock().unwrap();
28//!
29//!         if reactor.is_none() {
30//!             let r = Arc::new(Reactor { waiter: None });
31//!
32//!             let waiter = Arc::new(ReactorWaiter {
33//!                 reactor: Arc::downgrade(&r),
34//!             }).into();
35//!
36//!             // SAFETY: nobody else could be borrowing right now
37//!             let r = unsafe {
38//!                 let r = (Arc::into_raw(r) as *mut Reactor).as_mut().unwrap();
39//!                 r.waiter = Some(waiter);
40//!
41//!                 Arc::from_raw(r as *const Reactor)
42//!             };
43//!
44//!             *reactor = Some(r);
45//!         }
46//!
47//!         Arc::clone(reactor.as_ref().unwrap())
48//!     }
49//!
50//!     fn waiter<'a>(self: &'a Arc<Self>) -> &'a WakerWaiter {
51//!         self.waiter.as_ref().unwrap()
52//!     }
53//! }
54//!
55//! struct ReactorWaiter {
56//!     reactor: Weak<Reactor>,
57//! }
58//!
59//! impl WakerWait for ReactorWaiter {
60//!     fn wait(self: &Arc<Self>) {
61//!         // ... blocking poll for events ...
62//!         todo!();
63//!     }
64//!
65//!     fn canceler(self: &Arc<Self>) -> WakerWaiterCanceler {
66//!         // ... provide a way to unblock the above ...
67//!         todo!();
68//!     }
69//! }
70//!
71//! struct MyFuture;
72//!
73//! impl Future for MyFuture {
74//! #   type Output = ();
75//! #
76//!     fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
77//!         let p = match get_poller(cx) {
78//!             Some(p) => p,
79//!             None => panic!("MyFuture requires context to provide TopLevelPoller"),
80//!         };
81//!
82//!         if p.set_waiter(Reactor::current().waiter()).is_err() {
83//!             panic!("Incompatible waiter already assigned to TopLevelPoller");
84//!         }
85//!
86//!         // ... register waker, perform I/O, etc ...
87//! #       unimplemented!();
88//!     }
89//! }
90//! ```
91//!
92//! # Example of an executor providing a `TopLevelPoller`
93//!
94//! ```
95//! #![feature(local_waker)]
96//! #![feature(context_ext)]
97//! # use std::future::Future;
98//! # use std::mem::MaybeUninit;
99//! # use std::pin::{pin, Pin};
100//! # use std::sync::{Arc, Mutex};
101//! # use std::task::{Context, ContextBuilder, Poll, Wake};
102//! # use std::thread::{self, Thread};
103//! # use waker_waiter::{Anyable, SetWaiterError, TopLevelPoller, WakerWaiter};
104//! struct ThreadWaker {
105//!     thread: Thread,
106//!     waiter: Arc<Mutex<Option<WakerWaiter>>>,
107//! }
108//!
109//! impl Wake for ThreadWaker {
110//!     fn wake(self: Arc<Self>) {
111//!         if thread::current().id() == self.thread.id() {
112//!             // if we were woken in the same thread as execution,
113//!             // then the wake was caused by the WakerWaiter which
114//!             // will return control without any signaling needed
115//!             return;
116//!         }
117//!
118//!         let waiter = self.waiter.lock().unwrap().clone();
119//!
120//!         if let Some(waiter) = waiter {
121//!             // if a waiter was configured, then the execution thread
122//!             // will be blocking on it and we'll need to unblock it
123//!             waiter.canceler().cancel();
124//!         } else {
125//!             // if a waiter was not configured, then the execution
126//!             // thread will be asleep with a standard thread park
127//!             self.thread.unpark();
128//!         }
129//!     }
130//! }
131//!
132//! #[derive(Clone)]
133//! struct MyTopLevelPoller {
134//!     waiter: Arc<Mutex<Option<WakerWaiter>>>,
135//! }
136//!
137//! impl TopLevelPoller for MyTopLevelPoller {
138//!     fn set_waiter(&mut self, waiter: &WakerWaiter) -> Result<(), SetWaiterError> {
139//!         let self_waiter = &mut *self.waiter.lock().unwrap();
140//!
141//!         if let Some(cur) = self_waiter {
142//!             if cur == waiter {
143//!                 return Ok(()); // already set to this waiter
144//!             } else {
145//!                 return Err(SetWaiterError); // already set to a different waiter
146//!             }
147//!         }
148//!
149//!         *self_waiter = Some(waiter.clone());
150//!
151//!         Ok(())
152//!     }
153//! }
154//!
155//! let waiter = Arc::new(Mutex::new(None));
156//! let waker = Arc::new(ThreadWaker {
157//!     thread: thread::current(),
158//!     waiter: Arc::clone(&waiter),
159//! }).into();
160//! let mut cx = Context::from_waker(&waker);
161//! let mut poller = MyTopLevelPoller { waiter };
162//!
163//! let mut fut = pin!(async { /* ... */ });
164//!
165//! loop {
166//!    let result = {
167//!        let mut a = Anyable::new(&mut poller as &mut dyn TopLevelPoller);
168//!        let mut cx = ContextBuilder::from_waker(&waker).ext(a.as_any()).build();
169//!
170//!        fut.as_mut().poll(&mut cx)
171//!    };
172//!
173//!    match result {
174//!         Poll::Ready(res) => break res,
175//!         Poll::Pending => {
176//!             let waiter = poller.waiter.lock().unwrap().clone();
177//!
178//!             // if a waiter is configured then block on it. else do a
179//!             // standard thread park
180//!             match waiter {
181//!                 Some(waiter) => waiter.wait(),
182//!                 None => thread::park(),
183//!             }
184//!         }
185//!     }
186//! }
187//! ```
188
189#![feature(local_waker)]
190#![feature(context_ext)]
191
192use std::fmt;
193use std::mem::{self, transmute, ManuallyDrop};
194use std::ptr;
195use std::sync::Arc;
196use std::task::Context;
197
198pub struct RawCancelerVTable {
199    clone: unsafe fn(*const ()) -> RawCanceler,
200    cancel: unsafe fn(*const ()),
201    drop: unsafe fn(*const ()),
202}
203
204impl RawCancelerVTable {
205    pub const fn new(
206        clone: unsafe fn(_: *const ()) -> RawCanceler,
207        cancel: unsafe fn(_: *const ()),
208        drop: unsafe fn(_: *const ()),
209    ) -> Self {
210        Self {
211            clone,
212            cancel,
213            drop,
214        }
215    }
216}
217
218pub struct RawCanceler {
219    data: *const (),
220    vtable: &'static RawCancelerVTable,
221}
222
223impl RawCanceler {
224    #[inline]
225    pub const fn new(data: *const (), vtable: &'static RawCancelerVTable) -> Self {
226        Self { data, vtable }
227    }
228}
229
230pub struct WakerWaiterCanceler {
231    inner: RawCanceler,
232}
233
234impl WakerWaiterCanceler {
235    pub fn cancel(&self) {
236        unsafe { (self.inner.vtable.cancel)(self.inner.data) }
237    }
238
239    fn into_raw(mut self) -> RawCanceler {
240        const NOOP_VTABLE: &'static RawCancelerVTable =
241            &RawCancelerVTable::new(|c| RawCanceler::new(c, NOOP_VTABLE), |_| {}, |_| {});
242
243        mem::replace(&mut self.inner, RawCanceler::new(ptr::null(), NOOP_VTABLE))
244    }
245}
246
247impl Clone for WakerWaiterCanceler {
248    fn clone(&self) -> Self {
249        Self {
250            inner: unsafe { (self.inner.vtable.clone)(self.inner.data) },
251        }
252    }
253}
254
255impl Drop for WakerWaiterCanceler {
256    fn drop(&mut self) {
257        unsafe { (self.inner.vtable.drop)(self.inner.data) }
258    }
259}
260
261unsafe impl Send for WakerWaiterCanceler {}
262unsafe impl Sync for WakerWaiterCanceler {}
263
264#[derive(PartialEq)]
265pub struct RawWaiterVTable {
266    clone: unsafe fn(*const ()) -> RawWaiter,
267    wait: unsafe fn(*const ()),
268    canceler: unsafe fn(*const ()) -> Option<RawCanceler>,
269    drop: unsafe fn(*const ()),
270}
271
272impl RawWaiterVTable {
273    pub const fn new(
274        clone: unsafe fn(_: *const ()) -> RawWaiter,
275        wait: unsafe fn(_: *const ()),
276        canceler: unsafe fn(_: *const ()) -> Option<RawCanceler>,
277        drop: unsafe fn(_: *const ()),
278    ) -> Self {
279        Self {
280            clone,
281            wait,
282            canceler,
283            drop,
284        }
285    }
286}
287
288#[derive(PartialEq)]
289pub struct RawWaiter {
290    data: *const (),
291    vtable: &'static RawWaiterVTable,
292}
293
294impl RawWaiter {
295    #[inline]
296    pub const fn new(data: *const (), vtable: &'static RawWaiterVTable) -> Self {
297        Self { data, vtable }
298    }
299}
300
301#[derive(PartialEq)]
302pub struct WakerWaiter {
303    inner: RawWaiter,
304}
305
306impl WakerWaiter {
307    pub fn wait(&self) {
308        unsafe { (self.inner.vtable.wait)(self.inner.data) }
309    }
310
311    pub fn canceler(&self) -> WakerWaiterCanceler {
312        let raw = unsafe { (self.inner.vtable.canceler)(self.inner.data).unwrap() };
313
314        WakerWaiterCanceler { inner: raw }
315    }
316
317    pub fn to_local(self) -> LocalWakerWaiter {
318        let data = self.inner.data;
319        let vtable = self.inner.vtable;
320
321        mem::forget(self);
322
323        LocalWakerWaiter {
324            inner: RawWaiter { data, vtable },
325        }
326    }
327}
328
329impl Clone for WakerWaiter {
330    fn clone(&self) -> Self {
331        Self {
332            inner: unsafe { (self.inner.vtable.clone)(self.inner.data) },
333        }
334    }
335}
336
337impl Drop for WakerWaiter {
338    fn drop(&mut self) {
339        unsafe { (self.inner.vtable.drop)(self.inner.data) }
340    }
341}
342
343unsafe impl Send for WakerWaiter {}
344unsafe impl Sync for WakerWaiter {}
345
346#[derive(PartialEq)]
347pub struct LocalWakerWaiter {
348    inner: RawWaiter,
349}
350
351impl LocalWakerWaiter {
352    pub fn wait(&self) {
353        unsafe { (self.inner.vtable.wait)(self.inner.data) }
354    }
355
356    pub fn canceler(&self) -> Option<WakerWaiterCanceler> {
357        let raw = unsafe { (self.inner.vtable.canceler)(self.inner.data) };
358
359        raw.map(|v| WakerWaiterCanceler { inner: v })
360    }
361}
362
363impl Clone for LocalWakerWaiter {
364    fn clone(&self) -> Self {
365        Self {
366            inner: unsafe { (self.inner.vtable.clone)(self.inner.data) },
367        }
368    }
369}
370
371impl Drop for LocalWakerWaiter {
372    fn drop(&mut self) {
373        unsafe { (self.inner.vtable.drop)(self.inner.data) }
374    }
375}
376
377pub trait WakerWait {
378    fn wait(self: &Arc<Self>);
379    fn canceler(self: &Arc<Self>) -> WakerWaiterCanceler;
380}
381
382impl<W: WakerWait + Send + Sync + 'static> From<Arc<W>> for WakerWaiter {
383    fn from(waiter: Arc<W>) -> Self {
384        Self {
385            inner: raw_waiter(waiter),
386        }
387    }
388}
389
390#[inline(always)]
391fn raw_waiter<W: WakerWait + Send + Sync + 'static>(waiter: Arc<W>) -> RawWaiter {
392    struct VTablePerType<W>(W);
393
394    impl<W: WakerWait + Send + Sync + 'static> VTablePerType<W> {
395        const VTABLE: &'static RawWaiterVTable = &RawWaiterVTable::new(
396            clone_waiter::<W>,
397            wait::<W>,
398            canceler::<W>,
399            drop_waiter::<W>,
400        );
401    }
402
403    unsafe fn clone_waiter<W: WakerWait + Send + Sync + 'static>(waiter: *const ()) -> RawWaiter {
404        unsafe { Arc::increment_strong_count(waiter as *const W) };
405
406        RawWaiter::new(waiter as *const (), VTablePerType::<W>::VTABLE)
407    }
408
409    unsafe fn wait<W: WakerWait + Send + Sync + 'static>(waiter: *const ()) {
410        let waiter = unsafe { ManuallyDrop::new(Arc::from_raw(waiter as *const W)) };
411        <W as WakerWait>::wait(&waiter);
412    }
413
414    unsafe fn canceler<W: WakerWait + Send + Sync + 'static>(
415        waiter: *const (),
416    ) -> Option<RawCanceler> {
417        let waiter = unsafe { ManuallyDrop::new(Arc::from_raw(waiter as *const W)) };
418
419        Some(<W as WakerWait>::canceler(&waiter).into_raw())
420    }
421
422    unsafe fn drop_waiter<W: WakerWait + Send + Sync + 'static>(waiter: *const ()) {
423        unsafe { Arc::decrement_strong_count(waiter as *const W) };
424    }
425
426    RawWaiter::new(
427        Arc::into_raw(waiter) as *const (),
428        VTablePerType::<W>::VTABLE,
429    )
430}
431
432pub trait WakerWaiterCancel {
433    fn cancel(self: &Arc<Self>);
434}
435
436impl<C: WakerWaiterCancel + Send + Sync + 'static> From<Arc<C>> for WakerWaiterCanceler {
437    fn from(canceler: Arc<C>) -> Self {
438        Self {
439            inner: raw_canceler(canceler),
440        }
441    }
442}
443
444#[inline(always)]
445fn raw_canceler<C: WakerWaiterCancel + Send + Sync + 'static>(canceler: Arc<C>) -> RawCanceler {
446    struct VTablePerType<C>(C);
447
448    impl<C: WakerWaiterCancel + Send + Sync + 'static> VTablePerType<C> {
449        const VTABLE: &'static RawCancelerVTable =
450            &RawCancelerVTable::new(clone_canceler::<C>, cancel::<C>, drop_canceler::<C>);
451    }
452
453    unsafe fn clone_canceler<C: WakerWaiterCancel + Send + Sync + 'static>(
454        canceler: *const (),
455    ) -> RawCanceler {
456        unsafe { Arc::increment_strong_count(canceler as *const C) };
457
458        RawCanceler::new(canceler as *const (), VTablePerType::<C>::VTABLE)
459    }
460
461    unsafe fn cancel<C: WakerWaiterCancel + Send + Sync + 'static>(canceler: *const ()) {
462        let canceler = unsafe { ManuallyDrop::new(Arc::from_raw(canceler as *const C)) };
463        <C as WakerWaiterCancel>::cancel(&canceler);
464    }
465
466    unsafe fn drop_canceler<C: WakerWaiterCancel + Send + Sync + 'static>(canceler: *const ()) {
467        unsafe { Arc::decrement_strong_count(canceler as *const C) };
468    }
469
470    RawCanceler::new(
471        Arc::into_raw(canceler) as *const (),
472        VTablePerType::<C>::VTABLE,
473    )
474}
475
476#[derive(Debug)]
477pub struct SetWaiterError;
478
479impl fmt::Display for SetWaiterError {
480    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
481        write!(f, "Failed to set waiter: conflict")
482    }
483}
484
485#[derive(Debug)]
486pub enum SetLocalWaiterError {
487    Conflict,
488    Unsupported,
489}
490
491impl fmt::Display for SetLocalWaiterError {
492    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
493        match self {
494            Self::Conflict => write!(f, "Failed to set local waiter: conflict"),
495            Self::Unsupported => write!(f, "Failed to set local waiter: unsupported"),
496        }
497    }
498}
499
500pub trait TopLevelPoller {
501    fn set_waiter(&mut self, waiter: &WakerWaiter) -> Result<(), SetWaiterError>;
502
503    fn set_local_waiter(&mut self, _waiter: &LocalWakerWaiter) -> Result<(), SetLocalWaiterError> {
504        Err(SetLocalWaiterError::Unsupported)
505    }
506}
507
508pub mod ctx_ref {
509    use std::any::Any;
510    use std::marker::PhantomData;
511    use std::task::Context;
512
513    // SAFETY: only implement on dyn types that don't expose
514    // lifetimes held by the type. i.e. traits with methods
515    // that only work with argument lifetimes. this allows
516    // us to safely cast any held lifetimes, because there
517    // is no way to move-in, move-out, or obtain a reference
518    // to data with any such held lifetimes
519    pub unsafe trait DynWithStaticInterface {
520        type Static: ?Sized + 'static;
521        type Clamped<'a>: ?Sized
522        where
523            Self: 'a;
524
525        // return type is safe to use because it does not expose
526        // whatever lifetimes were converted to 'static
527        fn to_static(&mut self) -> &mut Self::Static;
528
529        // return type is safe to use because it does not expose
530        // whatever lifetimes were converted to 'a
531        fn to_clamped<'a>(&'a mut self) -> &'a mut Self::Clamped<'a>;
532    }
533
534    struct AnyablePrivate<T: ?Sized>(*mut T);
535
536    pub struct Anyable<'a, T: ?Sized, U: ?Sized> {
537        p: AnyablePrivate<T>,
538        _marker: PhantomData<&'a mut U>,
539    }
540
541    impl<'a, T: DynWithStaticInterface + ?Sized> Anyable<'a, T::Static, T> {
542        pub fn new(r: &'a mut T) -> Self {
543            Self {
544                p: AnyablePrivate(r.to_static()),
545                _marker: PhantomData,
546            }
547        }
548    }
549
550    impl<T: ?Sized + 'static, U: ?Sized> Anyable<'_, T, U> {
551        pub fn as_any<'a>(&'a mut self) -> &'a mut (dyn Any + 'static) {
552            &mut self.p
553        }
554    }
555
556    pub fn ctx_downcast<'a, T: DynWithStaticInterface + ?Sized + 'static>(
557        cx: &mut Context<'a>,
558    ) -> Option<&'a mut T::Clamped<'a>> {
559        let a = cx.ext();
560
561        let p = match a.downcast_mut::<AnyablePrivate<T>>() {
562            Some(p) => p,
563            None => return None,
564        };
565
566        // SAFETY: the inner pointer is guaranteed to be valid because
567        // p has the same lifetime as the reference that was
568        // originally casted to the pointer
569        let r: &'a mut T = unsafe { p.0.as_mut().unwrap() };
570
571        Some(r.to_clamped())
572    }
573}
574
575use ctx_ref::{ctx_downcast, DynWithStaticInterface};
576
577pub use ctx_ref::Anyable;
578
579// SAFETY: implementing on a dyn type that does not expose any lifetimes held by the type
580unsafe impl DynWithStaticInterface for (dyn TopLevelPoller + '_) {
581    type Static = dyn TopLevelPoller + 'static;
582    type Clamped<'a> = dyn TopLevelPoller + 'a;
583
584    fn to_static(&mut self) -> &mut Self::Static {
585        unsafe { transmute(self) }
586    }
587
588    fn to_clamped<'a>(&'a mut self) -> &'a mut Self::Clamped<'a> {
589        unsafe { transmute(self) }
590    }
591}
592
593pub fn get_poller<'a>(cx: &mut Context<'a>) -> Option<&'a mut (dyn TopLevelPoller + 'a)> {
594    ctx_downcast::<dyn TopLevelPoller>(cx)
595}
596
597mod executor {
598    use super::Anyable;
599    use super::{SetWaiterError, TopLevelPoller, WakerWaiter, WakerWaiterCanceler};
600    use std::future::Future;
601    use std::pin::pin;
602    use std::sync::{Arc, Mutex};
603    use std::task::{ContextBuilder, Poll, Wake};
604    use std::thread::{self, Thread};
605
606    struct ThreadWaker {
607        thread: Thread,
608        waiter_data: Arc<Mutex<Option<(WakerWaiter, WakerWaiterCanceler)>>>,
609    }
610
611    impl Wake for ThreadWaker {
612        fn wake(self: Arc<Self>) {
613            if thread::current().id() == self.thread.id() {
614                // if we were woken in the same thread as execution,
615                // then the wake was caused by the WakerWaiter which
616                // will return control without any signaling needed
617                return;
618            }
619
620            let waiter_data = self.waiter_data.lock().unwrap().clone();
621
622            if let Some(waiter_data) = waiter_data {
623                // if a waiter was configured, then the execution thread
624                // will be blocking on it and we'll need to unblock it
625                waiter_data.1.cancel();
626            } else {
627                // if a waiter was not configured, then the execution
628                // thread will be asleep with a standard thread park
629                self.thread.unpark();
630            }
631        }
632    }
633
634    #[derive(Clone)]
635    pub struct MyTopLevelPoller {
636        waiter_data: Arc<Mutex<Option<(WakerWaiter, WakerWaiterCanceler)>>>,
637    }
638
639    impl TopLevelPoller for MyTopLevelPoller {
640        fn set_waiter(&mut self, waiter: &WakerWaiter) -> Result<(), SetWaiterError> {
641            let waiter_data = &mut *self.waiter_data.lock().unwrap();
642
643            if let Some(cur) = waiter_data {
644                if cur.0 == *waiter {
645                    return Ok(()); // already set to this waiter
646                } else {
647                    return Err(SetWaiterError); // already set to a different waiter
648                }
649            }
650
651            *waiter_data = Some((waiter.clone(), waiter.canceler()));
652
653            Ok(())
654        }
655    }
656
657    pub fn block_on<T>(fut: T) -> T::Output
658    where
659        T: Future,
660    {
661        let waiter_data = Arc::new(Mutex::new(None));
662
663        let mut poller = MyTopLevelPoller {
664            waiter_data: Arc::clone(&waiter_data),
665        };
666
667        let waker = Arc::new(ThreadWaker {
668            thread: thread::current(),
669            waiter_data,
670        })
671        .into();
672
673        let mut fut = pin!(fut);
674
675        let res = loop {
676            let result = {
677                let mut a = Anyable::new(&mut poller as &mut dyn TopLevelPoller);
678                let mut cx = ContextBuilder::from_waker(&waker).ext(a.as_any()).build();
679
680                fut.as_mut().poll(&mut cx)
681            };
682
683            match result {
684                Poll::Ready(res) => break res,
685                Poll::Pending => {
686                    let waiter_data = poller.waiter_data.lock().unwrap().clone();
687
688                    // if a waiter is configured then block on it. else do a
689                    // standard thread park
690                    match waiter_data {
691                        Some(waiter_data) => waiter_data.0.wait(),
692                        None => thread::park(),
693                    }
694                }
695            }
696        };
697
698        res
699    }
700}
701
702pub use executor::block_on;
703
704#[cfg(test)]
705mod tests {
706    use super::*;
707    use std::cell::RefCell;
708    use std::future::Future;
709    use std::pin::{pin, Pin};
710    use std::task::{ContextBuilder, Poll, Wake};
711
712    struct NoopWaker;
713
714    impl Wake for NoopWaker {
715        fn wake(self: Arc<Self>) {}
716    }
717
718    struct MyTopLevelPoller {
719        waiter: RefCell<Option<WakerWaiter>>,
720    }
721
722    impl TopLevelPoller for MyTopLevelPoller {
723        fn set_waiter(&mut self, waiter: &WakerWaiter) -> Result<(), SetWaiterError> {
724            let self_waiter = &mut *self.waiter.borrow_mut();
725
726            if let Some(cur) = self_waiter {
727                if cur == waiter {
728                    return Ok(()); // already set to this waiter
729                } else {
730                    return Err(SetWaiterError); // already set to a different waiter
731                }
732            }
733
734            *self_waiter = Some(waiter.clone());
735
736            Ok(())
737        }
738    }
739
740    struct NoopWakerWaiterCanceler;
741
742    impl WakerWaiterCancel for NoopWakerWaiterCanceler {
743        fn cancel(self: &Arc<Self>) {}
744    }
745
746    struct NoopWakerWaiter;
747
748    impl WakerWait for NoopWakerWaiter {
749        fn wait(self: &Arc<Self>) {}
750        fn canceler(self: &Arc<Self>) -> WakerWaiterCanceler {
751            Arc::new(NoopWakerWaiterCanceler).into()
752        }
753    }
754
755    struct MyFuture {
756        waiter: WakerWaiter,
757    }
758
759    impl MyFuture {
760        fn new() -> Self {
761            Self {
762                waiter: Arc::new(NoopWakerWaiter).into(),
763            }
764        }
765    }
766
767    impl Future for MyFuture {
768        type Output = ();
769
770        fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
771            // first, apply WakerWaiter
772            // NOTE: alternatively, the lookup/set could happen when MyFuture
773            // is constructed (or when some parent owner is constructed)
774
775            let waker = Arc::new(NoopWaker).into();
776            let mut cx1 = ContextBuilder::from(cx).waker(&waker).build();
777
778            // should be cheap
779            let poller = match get_poller(&mut cx1) {
780                Some(p) => p,
781                None => panic!("MyFuture requires context to provide TopLevelPoller"),
782            };
783
784            // can be cheap: it's up to the setter impl, but this
785            // could just be a pointer comparison
786            if poller.set_waiter(&self.waiter).is_err() {
787                panic!("Incompatible WakerWaiter already assigned to context's TopLevelPoller");
788            }
789
790            Poll::Ready(())
791        }
792    }
793
794    struct MyFuture2 {
795        waiter: WakerWaiter,
796    }
797
798    impl MyFuture2 {
799        fn new() -> Self {
800            Self {
801                waiter: Arc::new(NoopWakerWaiter).into(),
802            }
803        }
804    }
805
806    impl Future for MyFuture2 {
807        type Output = ();
808
809        fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
810            // first, apply WakerWaiter
811            // NOTE: alternatively, the lookup/set could happen when MyFuture
812            // is constructed (or when some parent owner is constructed)
813
814            let waker = Arc::new(NoopWaker).into();
815            let mut cx1 = ContextBuilder::from(cx).waker(&waker).build();
816
817            // should be cheap
818            let poller = match get_poller(&mut cx1) {
819                Some(p) => p,
820                None => panic!("MyFuture requires context to provide TopLevelPoller"),
821            };
822
823            // can be cheap: it's up to the setter impl, but this
824            // could just be a pointer comparison
825            if poller.set_waiter(&self.waiter).is_err() {
826                panic!("Incompatible WakerWaiter already assigned to context's TopLevelPoller");
827            }
828
829            Poll::Ready(())
830        }
831    }
832
833    #[test]
834    fn test_waiter() {
835        let waker = Arc::new(NoopWaker).into();
836
837        let mut poller = MyTopLevelPoller {
838            waiter: RefCell::new(None),
839        };
840
841        let mut fut = pin!(MyFuture::new());
842
843        loop {
844            let result = {
845                let mut a = Anyable::new(&mut poller as &mut dyn TopLevelPoller);
846                let mut cx = ContextBuilder::from_waker(&waker).ext(a.as_any()).build();
847
848                fut.as_mut().poll(&mut cx)
849            };
850
851            match result {
852                Poll::Ready(res) => break res,
853                Poll::Pending => match &*poller.waiter.borrow() {
854                    Some(waiter) => waiter.wait(),
855                    None => {}
856                },
857            }
858        }
859    }
860
861    #[test]
862    fn test_block_on() {
863        block_on(MyFuture2::new());
864    }
865}