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}