aeth_task/ready_poll.rs
1//! Make futures to be ready-pollable.
2//!
3//! This is suitable for the user who wants to
4//! know whether a future has been polled to
5//! ready by the async runtime. We provide a
6//! mechanism of wrapping a future and returning
7//! a poller to observe the readiness.
8//!
9//! This is not commonly required for a task
10//! writer, which should rely on the async/await
11//! primitives to observe the readines. So we
12//! pick this module out of the crate root.
13
14use futures::FutureExt;
15use futures::future::{BoxFuture, LocalBoxFuture};
16use std::pin::Pin;
17use std::sync::Arc;
18use std::sync::atomic::{AtomicBool, Ordering};
19use std::task::{Context, Poll};
20
21#[derive(Clone)]
22struct ReadyInner {
23 // XXX: We pay the price of using atomic operations
24 // for whichever kind of future, given that the
25 // price of an atomic operation is not unaffordable
26 // compared to other operations to be done in the
27 // system. This also reduce the chance of misuse.
28 ready: Arc<AtomicBool>,
29}
30
31impl ReadyInner {
32 fn new() -> Self {
33 Self {
34 ready: Arc::new(AtomicBool::new(false)),
35 }
36 }
37
38 fn ready(&self) -> bool {
39 self.ready.load(Ordering::SeqCst)
40 }
41
42 fn notify(&self) {
43 self.ready.store(true, Ordering::SeqCst);
44 }
45}
46
47/// Future wrapper to be ready-pollable.
48///
49/// This wrappr capture the lifecycle and polling of
50/// the underlying future. Whenever the future is
51/// destroyed or polled to ready, it will set the
52/// ready flag so that the ready state of this
53/// future can be tested later.
54pub struct ReadyPollFuture<'a, T> {
55 ready: ReadyInner,
56 future: BoxFuture<'a, T>,
57}
58
59impl<'a, T> Drop for ReadyPollFuture<'a, T> {
60 fn drop(&mut self) {
61 // XXX: this is required when we are combining
62 // the future with Remote, which may cancel
63 // the future. The readiness will be
64 // broadcasted when it's dropped.
65 self.ready.notify();
66 }
67}
68
69impl<'a, T> Future for ReadyPollFuture<'a, T> {
70 type Output = T;
71
72 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
73 // XXX: for simplicity, we don't handle the
74 // case when future.poll panics. This will be
75 // handled by its caller, especially when
76 // used with Remote, to drop ReadyPollFuture
77 // and then notify readiness there.
78 let result = self.future.poll_unpin(cx);
79 if result.is_ready() {
80 self.ready.notify();
81 }
82 result
83 }
84}
85
86/// Ready poller object.
87///
88/// This is the tester side result of the ready
89/// poll, providing `ready()` method to check if
90/// the wrapped future is ready.
91pub struct ReadyPoll {
92 ready: ReadyInner,
93}
94
95impl ReadyPoll {
96 pub fn ready(&self) -> bool {
97 self.ready.ready()
98 }
99}
100
101/// Wraps the future to be ready-pollable.
102///
103/// The future is thought to be ready when the
104/// future is **polled to be ready** or destroyed.
105/// It's not suitable for scenario to capture the
106/// ready state without resuming its processing.
107///
108/// This is useful from outside the async runtime,
109/// where no async context is available. This
110/// wrapper smuggles the ready state of a specific
111/// future out of the async runtime.
112pub fn ready_poll<'a, T, F>(future: F) -> (ReadyPollFuture<'a, T>, ReadyPoll)
113where
114 F: Future<Output = T> + Send + 'a,
115{
116 let ready = ReadyInner::new();
117 let ready1 = ready.clone();
118 (
119 ReadyPollFuture {
120 ready,
121 future: Box::pin(future),
122 },
123 ReadyPoll { ready: ready1 },
124 )
125}
126
127/// Local future wrapper to be ready-pollable.
128pub struct LocalReadyPollFuture<'a, T> {
129 ready: ReadyInner,
130 future: LocalBoxFuture<'a, T>,
131}
132
133impl<'a, T> Drop for LocalReadyPollFuture<'a, T> {
134 fn drop(&mut self) {
135 self.ready.notify();
136 }
137}
138
139impl<'a, T> Future for LocalReadyPollFuture<'a, T> {
140 type Output = T;
141
142 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
143 let result = self.future.poll_unpin(cx);
144 if result.is_ready() {
145 self.ready.notify();
146 }
147 result
148 }
149}
150
151/// Wraps the local future to be ready pollable.
152///
153/// This is the local version of the `ready_poll`
154/// counterpart. You will need this when your
155/// future is `!Send`, which is allowed in the
156/// case of a foreground thread.
157///
158/// This method also assumes that the future and
159/// poller runs on the same thread, in which no
160/// atomic operation is required.
161pub fn local_ready_poll<'a, T, F>(future: F) -> (LocalReadyPollFuture<'a, T>, ReadyPoll)
162where
163 F: Future<Output = T> + 'a,
164{
165 let ready = ReadyInner::new();
166 let ready1 = ready.clone();
167 (
168 LocalReadyPollFuture {
169 ready,
170 future: Box::pin(future),
171 },
172 ReadyPoll { ready: ready1 },
173 )
174}