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
//! Delay

use core::pin::Pin;
use core::future::Future;
use core::{task, time};

use crate::{PlatformTimer, Timer};
use crate::state::TimerState;

use crate::alloc::boxed::Box;

enum State<T> {
    Init,
    Active(Box<TimerState>, T)
}

#[must_use = "Delay does nothing unless polled"]
///Future that resolves sometime in future
///
///## Implementation notes
///
///When `Future` is created, timer is not yet started.
///The actual timer will start only after future will be initally polled.
///
///After timer expires, executor will be notified and next call to `Future::poll` shall
///return `Ready`, after which all further calls to `Future::poll` result in `Pending`
///without restarting timer.
///
///## Usage
///
///```rust,no_run
/// use async_timer::Delay;
/// use core::time;
///
/// Delay::platform_new(time::Duration::from_secs(2));
///```
pub struct Delay<T=PlatformTimer> {
    pub(crate) timeout: time::Duration,
    state: State<T>
}

impl Delay {
    ///Creates new instance using [PlatformTimer](../type.PlatformTimer.html)
    pub fn platform_new(timeout: time::Duration) -> Self {
        Self {
            timeout,
            state: State::Init,
        }
    }
}

impl<T: Timer> Delay<T> {
    ///Creates new instance with specified timeout
    ///
    ///Requires to specify `Timer` type (e.g. `Delay::<PlatformTimer>::new()`)
    pub fn new(timeout: time::Duration) -> Self {
        Self {
            timeout,
            state: State::Init,
        }
    }

    ///Restarts underlying `Timer`.
    ///
    ///Comparing to creating `Delay`
    ///the `Timer` will start counting immediately.
    pub fn restart(&mut self, ctx: &task::Context) {
        match self.state {
            State::Init => (),
            State::Active(ref mut _state, ref mut timer) => {
                match timer.state().is_done() {
                    true => (),
                    false => timer.reset(),
                }

                timer.register_waker(ctx.waker());
                timer.start_delay(self.timeout)
            }
        }
    }
}

impl<T: Timer> Future for Delay<T> {
    type Output = ();

    fn poll(mut self: Pin<&mut Self>, ctx: &mut task::Context) -> task::Poll<Self::Output> {
        self.state = match &self.state {
            State::Init => {
                let state = Box::into_raw(Box::new(TimerState::new()));
                let mut timer = T::new(state);
                let state = unsafe { Box::from_raw(state) };
                assert!(state.is_done());

                timer.register_waker(ctx.waker());
                timer.start_delay(self.timeout);

                State::Active(state, timer)
            },
            State::Active(ref _state, ref timer) => match timer.state().is_done() {
                true => return task::Poll::Ready(()),
                false => return task::Poll::Pending,
            }
        };

        task::Poll::Pending
    }
}