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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
//! Frame clock module
//!
//! Contains a clocking that ticks in a fixed interval as precisely as
//! possible.

// FIXME: clock should start immediately, not waiting the initial interval

use std::{iter, thread, time};

/// Clock structure.
pub struct Clock {
    /// Start time of the clock, in ns since epoch
    started_at: time::Instant,
    /// Tick length
    tick_len: time::Duration,
}

/// A clock iterator
///
/// Used to iterate over the clock:
///
/// ```
/// use std::time;
/// use ticktock::Clock;
///
/// let start = time::Instant::now();
/// // ticks once per second
/// let mut clock = Clock::new(time::Duration::from_secs(1));
///
/// // as soon as the clock starts, it will wait for the next tick.
/// // in this case, we'll start at t = 1 second
/// for tick in clock.iter() {
///     // ...
///
///     // a simple break will exit
///     break;
/// }
///
/// let end = time::Instant::now();
///
/// assert!(time::Duration::from_secs(1) < end - start);
/// ```
pub struct ClockIter<'a>(&'a Clock);

impl Clock {
    /// Creates a new clock.
    ///
    /// Create a clock with a tick size of `tick_len_ms`, in ms.
    #[inline]
    pub fn new(tick_len: time::Duration) -> Clock {
        Clock::new_with_start_time(tick_len, time::Instant::now())
    }

    /// Creates a new clock with a specified start time
    #[inline]
    pub fn new_with_start_time(tick_len: time::Duration, start: time::Instant) -> Clock {
        Clock {
            started_at: start,
            tick_len,
        }
    }

    /// Creates a new fixed-framerate clock
    #[inline]
    pub fn framerate(fps: f64) -> Clock {
        Clock::framerate_with_start_time(fps, time::Instant::now())
    }

    /// Creates a new fixed-framerate clock with a specified sart time
    #[inline]
    pub fn framerate_with_start_time(fps: f64, start: time::Instant) -> Clock {
        let frame_time_s = 1.0 / fps;

        Clock::new_with_start_time(time::Duration::from_secs_f64(frame_time_s), start)
    }

    /// Creates a new clock with a different tick length that is synced to
    /// the original clock
    #[inline]
    pub fn synced(&self, tick_len: time::Duration) -> Clock {
        Clock {
            started_at: self.started_at,
            tick_len,
        }
    }

    /// Get start time
    #[inline]
    pub fn started_at(&self) -> time::Instant {
        self.started_at
    }

    /// Returns the tick number preceding an specific instant in time
    #[inline]
    pub fn tick_num_at(&self, now: time::Instant) -> u128 {
        (now - self.started_at).as_nanos() / self.tick_len.as_nanos()
    }

    /// Waits for the next clock tick.
    ///
    /// Will wait until the next tick and return the current tick count.
    #[inline]
    pub fn wait_until_tick(&self) -> (u128, time::Instant) {
        // uses signed math because ntp might put us in the past
        let now = time::Instant::now();

        let current_tick_num = self.tick_num_at(now);
        let next_tick_num = current_tick_num + 1;

        let next_tick = self.started_at + self.tick_len * next_tick_num as u32;
        let until_next: time::Duration = next_tick - now;

        thread::sleep(until_next);
        (next_tick_num, next_tick)
    }

    /// Creates a clock iterator.
    ///
    /// The iterator will iterate forever, calling `wait_until_tick` on each
    /// iteration. It will panic after about 293 years.
    ///
    /// Returns (current tick number, absolute time) on each iteration, where
    /// absolute time is relative to a fixed offset that depends on the machine
    /// (see `Instant`).
    #[inline]
    pub fn iter(&self) -> ClockIter {
        ClockIter(self)
    }

    /// Create a relative clock iterator.
    ///
    /// Similar to `iter()`, but the resulting iterator will return a tuple of
    /// (current tick number, relative time), with relative time being a
    /// `time::Duration` from the start of the clock.
    #[inline]
    pub fn rel_iter(&self) -> ClockIterRelative {
        ClockIterRelative(self)
    }
}

impl<'a> iter::Iterator for ClockIter<'a> {
    type Item = (u128, time::Instant);

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        Some(self.0.wait_until_tick())
    }
}

/// Similar to `ClockIter`, but returns a relative time instead.
///
/// The resulting returned tuple will be of the form `(tick_number,
/// duration_since_clock_start)`
pub struct ClockIterRelative<'a>(&'a Clock);

impl<'a> iter::Iterator for ClockIterRelative<'a> {
    type Item = (u128, time::Duration);

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        let (n, t) = self.0.wait_until_tick();
        Some((n, t - self.0.started_at))
    }
}