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;
}