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}