1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Simple waiter trait for synchronous actions.
//!
//! The `Waiter` thread represents some action that can be polled for, and
//! that can also fail.

use std::thread::sleep;
use std::time::{Duration, Instant};

/// Trait representing a waiter for some asynchronous action to finish.
///
/// The type `T` is the final type of the action, `E` is an error.
pub trait Waiter<T, E> {
    /// Default timeout for this action.
    ///
    /// This timeout is used in the `wait` method.
    /// If `None, wait forever by default.
    fn default_wait_timeout(&self) -> Option<Duration>;

    /// Default delay between two retries.
    fn default_delay(&self) -> Duration;

    /// Update the current state of the action.
    ///
    /// Returns `T` if the action is finished, `None` if it is not. All errors
    /// are propagated via the `Result`.
    ///
    /// This method should not be called again after it returned the final
    /// result.
    fn poll(&mut self) -> Result<Option<T>, E>;

    /// Error to return on timeout.
    fn timeout_error(&self) -> E;

    /// Wait for the default amount of time.
    ///
    /// Consumes the `Waiter`.
    /// Returns `OperationTimedOut` if the timeout is reached.
    fn wait(self) -> Result<T, E>
    where
        Self: Sized,
    {
        match self.default_wait_timeout() {
            Some(duration) => self.wait_for(duration),
            None => self.wait_forever(),
        }
    }

    /// Wait for specified amount of time.
    ///
    /// Returns `OperationTimedOut` if the timeout is reached.
    fn wait_for(self, duration: Duration) -> Result<T, E>
    where
        Self: Sized,
    {
        let delay = self.default_delay();
        self.wait_for_with_delay(duration, delay)
    }

    /// Wait for specified amount of time.
    fn wait_for_with_delay(mut self, duration: Duration, delay: Duration) -> Result<T, E>
    where
        Self: Sized,
    {
        let start = Instant::now();
        while Instant::now().duration_since(start) <= duration {
            if let Some(result) = self.poll()? {
                return Ok(result);
            };
            sleep(delay);
        }
        Err(self.timeout_error())
    }

    /// Wait forever.
    fn wait_forever(self) -> Result<T, E>
    where
        Self: Sized,
    {
        let delay = self.default_delay();
        self.wait_forever_with_delay(delay)
    }

    /// Wait forever with given delay between attempts.
    fn wait_forever_with_delay(mut self, delay: Duration) -> Result<T, E>
    where
        Self: Sized,
    {
        loop {
            if let Some(result) = self.poll()? {
                return Ok(result);
            };
            sleep(delay);
        }
    }
}

/// Current state of the waiter.
///
/// Type `T` is the current state of the resource, and does not have to match
/// type `T` of `Waiter<T>`.
pub trait WaiterCurrentState<T> {
    /// Get the current representation of the resource.
    ///
    /// Valid as of the last `poll` call.
    fn waiter_current_state(&self) -> &T;
}