pub type Milliseconds = u32;
pub type Microseconds = u64;
pub trait TimeProvider {
fn current_time_ms(&self) -> Milliseconds;
fn current_time_us(&self) -> Microseconds;
fn elapsed_ms(&mut self) -> Milliseconds {
let current = self.current_time_ms();
let last = self.last_time_ms();
self.update_last_time_ms(current);
current.saturating_sub(last)
}
fn elapsed_us(&mut self) -> Microseconds {
let current = self.current_time_us();
let last = self.last_time_us();
self.update_last_time_us(current);
current.saturating_sub(last)
}
fn last_time_ms(&self) -> Milliseconds;
fn last_time_us(&self) -> Microseconds;
fn update_last_time_ms(&mut self, time: Milliseconds);
fn update_last_time_us(&mut self, time: Microseconds);
fn reset(&mut self) {
let current_ms = self.current_time_ms();
let current_us = self.current_time_us();
self.update_last_time_ms(current_ms);
self.update_last_time_us(current_us);
}
}
#[derive(Debug)]
pub struct MonotonicTimeProvider<F>
where
F: Fn() -> Microseconds,
{
timer_fn: F,
last_ms: Milliseconds,
last_us: Microseconds,
}
impl<F> MonotonicTimeProvider<F>
where
F: Fn() -> Microseconds,
{
pub fn new(timer_fn: F) -> Self {
let current_us = timer_fn();
Self {
timer_fn,
last_ms: (current_us / 1000) as Milliseconds,
last_us: current_us,
}
}
pub fn from_ticks<G>(
get_ticks: G,
ticks_per_second: u32,
) -> MonotonicTimeProvider<impl Fn() -> Microseconds>
where
G: Fn() -> u64,
{
let timer_fn = move || {
let ticks = get_ticks();
(ticks * 1_000_000) / ticks_per_second as u64
};
let current_us = timer_fn();
MonotonicTimeProvider {
timer_fn,
last_ms: (current_us / 1000) as Milliseconds,
last_us: current_us,
}
}
}
impl<F> TimeProvider for MonotonicTimeProvider<F>
where
F: Fn() -> Microseconds,
{
fn current_time_ms(&self) -> Milliseconds {
((self.timer_fn)() / 1000) as Milliseconds
}
fn current_time_us(&self) -> Microseconds {
(self.timer_fn)()
}
fn last_time_ms(&self) -> Milliseconds {
self.last_ms
}
fn last_time_us(&self) -> Microseconds {
self.last_us
}
fn update_last_time_ms(&mut self, time: Milliseconds) {
self.last_ms = time;
}
fn update_last_time_us(&mut self, time: Microseconds) {
self.last_us = time;
}
}
#[derive(Debug, Clone)]
pub struct ManualTimeProvider {
current_us: Microseconds,
last_ms: Milliseconds,
last_us: Microseconds,
}
impl ManualTimeProvider {
pub fn new() -> Self {
Self {
current_us: 0,
last_ms: 0,
last_us: 0,
}
}
pub fn with_start_time(start_us: Microseconds) -> Self {
Self {
current_us: start_us,
last_ms: (start_us / 1000) as Milliseconds,
last_us: start_us,
}
}
pub fn advance_ms(&mut self, delta_ms: Milliseconds) {
self.current_us += (delta_ms as Microseconds) * 1000;
}
pub fn advance_us(&mut self, delta_us: Microseconds) {
self.current_us += delta_us;
}
pub fn set_time_us(&mut self, time_us: Microseconds) {
self.current_us = time_us;
}
pub fn set_time_ms(&mut self, time_ms: Milliseconds) {
self.current_us = (time_ms as Microseconds) * 1000;
}
}
impl Default for ManualTimeProvider {
fn default() -> Self {
Self::new()
}
}
impl TimeProvider for ManualTimeProvider {
fn current_time_ms(&self) -> Milliseconds {
(self.current_us / 1000) as Milliseconds
}
fn current_time_us(&self) -> Microseconds {
self.current_us
}
fn last_time_ms(&self) -> Milliseconds {
self.last_ms
}
fn last_time_us(&self) -> Microseconds {
self.last_us
}
fn update_last_time_ms(&mut self, time: Milliseconds) {
self.last_ms = time;
}
fn update_last_time_us(&mut self, time: Microseconds) {
self.last_us = time;
}
}
#[cfg(feature = "std")]
#[derive(Debug)]
pub struct StdTimeProvider {
start_time: std::time::Instant,
last_ms: Milliseconds,
last_us: Microseconds,
}
#[cfg(feature = "std")]
impl StdTimeProvider {
pub fn new() -> Self {
let now = std::time::Instant::now();
Self {
start_time: now,
last_ms: 0,
last_us: 0,
}
}
}
#[cfg(feature = "std")]
impl Default for StdTimeProvider {
fn default() -> Self {
Self::new()
}
}
#[cfg(feature = "std")]
impl TimeProvider for StdTimeProvider {
fn current_time_ms(&self) -> Milliseconds {
self.start_time.elapsed().as_millis() as Milliseconds
}
fn current_time_us(&self) -> Microseconds {
self.start_time.elapsed().as_micros() as Microseconds
}
fn last_time_ms(&self) -> Milliseconds {
self.last_ms
}
fn last_time_us(&self) -> Microseconds {
self.last_us
}
fn update_last_time_ms(&mut self, time: Milliseconds) {
self.last_ms = time;
}
fn update_last_time_us(&mut self, time: Microseconds) {
self.last_us = time;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_manual_time_provider() {
let mut provider = ManualTimeProvider::new();
assert_eq!(provider.current_time_ms(), 0);
assert_eq!(provider.current_time_us(), 0);
provider.advance_ms(100);
assert_eq!(provider.current_time_ms(), 100);
assert_eq!(provider.current_time_us(), 100_000);
provider.advance_us(500);
assert_eq!(provider.current_time_ms(), 100);
assert_eq!(provider.current_time_us(), 100_500);
}
#[test]
fn test_manual_time_provider_elapsed() {
let mut provider = ManualTimeProvider::new();
assert_eq!(provider.elapsed_ms(), 0);
provider.advance_ms(50);
assert_eq!(provider.elapsed_ms(), 50);
provider.advance_ms(25);
assert_eq!(provider.elapsed_ms(), 25);
}
#[test]
fn test_monotonic_time_provider() {
use core::cell::RefCell;
let counter = RefCell::new(0u64);
let timer_fn = || {
let mut c = counter.borrow_mut();
*c += 1000; *c
};
let provider = MonotonicTimeProvider::new(timer_fn);
let first_time = provider.current_time_us();
let second_time = provider.current_time_us();
assert!(second_time > first_time);
assert_eq!(second_time - first_time, 1000); }
#[cfg(feature = "std")]
#[test]
fn test_std_time_provider() {
let provider = StdTimeProvider::new();
let first_time = provider.current_time_ms();
std::thread::sleep(std::time::Duration::from_millis(10));
let second_time = provider.current_time_ms();
assert!(second_time >= first_time + 10);
}
#[test]
fn test_time_provider_reset() {
let mut provider = ManualTimeProvider::new();
provider.advance_ms(100);
let _ = provider.elapsed_ms();
provider.advance_ms(50);
provider.reset();
provider.advance_ms(25);
let elapsed = provider.elapsed_ms();
assert_eq!(elapsed, 25); }
}