waiter/
lib.rs

1// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
2// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
3// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
4// option. This file may not be copied, modified, or distributed
5// except according to those terms.
6
7//! Simple waiter trait for synchronous actions.
8//!
9//! The `Waiter` thread represents some action that can be polled for, and
10//! that can also fail.
11
12use async_trait::async_trait;
13use tokio::time::sleep;
14use tokio::time::{Duration, Instant};
15
16/// Trait representing a waiter for some asynchronous action to finish.
17///
18/// The type `T` is the final type of the action, `E` is an error.
19#[async_trait]
20pub trait Waiter<T, E> {
21    /// Default timeout for this action.
22    ///
23    /// This timeout is used in the `wait` method.
24    /// If `None, wait forever by default.
25    fn default_wait_timeout(&self) -> Option<Duration>;
26
27    /// Default delay between two retries.
28    fn default_delay(&self) -> Duration;
29
30    /// Update the current state of the action.
31    ///
32    /// Returns `T` if the action is finished, `None` if it is not. All errors
33    /// are propagated via the `Result`.
34    ///
35    /// This method should not be called again after it returned the final
36    /// result.
37    async fn poll(&mut self) -> Result<Option<T>, E>;
38
39    /// Error to return on timeout.
40    fn timeout_error(&self) -> E;
41
42    /// Wait for the default amount of time.
43    ///
44    /// Consumes the `Waiter`.
45    /// Returns `OperationTimedOut` if the timeout is reached.
46    async fn wait(self) -> Result<T, E>
47    where
48        Self: Sized,
49    {
50        let duration = self.default_wait_timeout();
51        match duration {
52            Some(duration) => self.wait_for(duration).await,
53            None => self.wait_forever().await,
54        }
55    }
56
57    /// Wait for specified amount of time.
58    ///
59    /// Returns `OperationTimedOut` if the timeout is reached.
60    async fn wait_for(self, duration: Duration) -> Result<T, E>
61    where
62        Self: Sized,
63    {
64        let delay = self.default_delay();
65        self.wait_for_with_delay(duration, delay).await
66    }
67
68    /// Wait for specified amount of time.
69    async fn wait_for_with_delay(mut self, duration: Duration, delay: Duration) -> Result<T, E>
70    where
71        Self: Sized,
72    {
73        let start = Instant::now();
74        while Instant::now().duration_since(start) <= duration {
75            if let Some(result) = self.poll().await? {
76                return Ok(result);
77            };
78            sleep(delay).await;
79        }
80        Err(self.timeout_error())
81    }
82
83    /// Wait forever.
84    async fn wait_forever(self) -> Result<T, E>
85    where
86        Self: Sized,
87    {
88        let delay = self.default_delay();
89        self.wait_forever_with_delay(delay).await
90    }
91
92    /// Wait forever with given delay between attempts.
93    async fn wait_forever_with_delay(mut self, delay: Duration) -> Result<T, E>
94    where
95        Self: Sized,
96    {
97        loop {
98            if let Some(result) = self.poll().await? {
99                return Ok(result);
100            };
101            sleep(delay).await;
102        }
103    }
104}
105
106/// Current state of the waiter.
107///
108/// Type `T` is the current state of the resource, and does not have to match
109/// type `T` of `Waiter<T>`.
110pub trait WaiterCurrentState<T> {
111    /// Get the current representation of the resource.
112    ///
113    /// Valid as of the last `poll` call.
114    fn waiter_current_state(&self) -> &T;
115}