async-timer 1.0.0-beta.15

Timers for Rust async story
Documentation
use async_timer::Interval;
use tokio_1 as tokio;

use std::time;

#[tokio::test]
async fn test_interval() {
    let mut interval = Interval::platform_new(time::Duration::from_secs(1));

    let before = time::SystemTime::now();
    interval.wait().await;
    let after = time::SystemTime::now();
    let diff = after.duration_since(before).unwrap();

    assert!(diff.as_millis() >= 750 && diff.as_millis() <= 1_250);

    let before = time::SystemTime::now();
    interval.wait().await;
    let after = time::SystemTime::now();
    let diff = after.duration_since(before).unwrap();

    assert!(diff.as_millis() >= 750 && diff.as_millis() <= 1_250);
}

async fn test_interval_average(num_runs: usize, interval: time::Duration) {
    const ACCURACY: time::Duration = time::Duration::from_nanos(133333);

    let mut times = Vec::with_capacity(num_runs);

    println!("interval={:?}", interval);
    let mut timer = async_timer::interval(interval);

    for _ in 0..num_runs {
        let start = std::time::Instant::now();

        timer.wait().await;

        // simulate some work, this doesn't have to be consistent
        // the timer is the only thing that needs to be consistent
        std::thread::sleep(time::Duration::from_millis(1));

        // log time, the timer should be waiting less
        // to account for the time it took to do the work
        times.push(start.elapsed());
    }

    let total: time::Duration = times.iter().sum();
    let average = total / num_runs as u32;

    let min = interval - ACCURACY;
    let max = interval + ACCURACY;
    println!("Check {:?} <= average={:?} <= {:?}", min, average, max);
    //Margin of error should be within interval-0.1ms..=interval+0.1ms
    assert!(min <= average);
    assert!(average <= max);
}

//Windows timers are shite for small duration
//kevent() also behaves badly for some reason
//only linux's timerfd is reliable
#[tokio::test]
#[cfg(feature = "tokio1")]
#[cfg(target_os = "linux")]
async fn test_average_of_small_interval() {
    test_interval_average(6000, time::Duration::from_secs_f32(1. / 120.)).await;
}

#[tokio::test]
#[cfg(feature = "tokio1")]
#[cfg(target_os = "linux")]
async fn test_average_of_mid_interval() {
    test_interval_average(60, time::Duration::from_secs_f32(135. / 120.)).await;
}