timeout-trait 0.8.1

Traits used to wait and timeout.
Documentation
use crate::*;

pub struct TickTimeout<T: TickInstant> {
    time: T,
    timeout: TickDuration<T>,
}

impl<T> TickTimeout<T>
where
    T: TickInstant,
{
    pub fn nanos(timeout: u32) -> Self {
        Self::new(TickDuration::nanos(timeout))
    }

    pub fn micros(timeout: u32) -> Self {
        Self::new(TickDuration::micros(timeout))
    }

    pub fn millis(timeout: u32) -> Self {
        Self::new(TickDuration::millis(timeout))
    }

    pub fn new(timeout: TickDuration<T>) -> Self {
        Self {
            time: T::now(),
            timeout,
        }
    }

    /// Can be reused without calling `restart()`.
    #[inline]
    pub fn timeout(&mut self) -> bool {
        if self.time.timeout(&self.timeout) {
            self.time.move_forward(&self.timeout);
            return true;
        }
        false
    }

    #[inline(always)]
    pub fn restart(&mut self) {
        self.time = T::now();
    }

    #[inline]
    pub fn time_left(&mut self) -> TickDuration<T> {
        self.time.time_left(&self.timeout)
    }
}

impl<T> From<&TickDuration<T>> for TickTimeout<T>
where
    T: TickInstant,
{
    fn from(value: &TickDuration<T>) -> Self {
        Self::new(value.clone())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::mock::MockInstant;
    use fugit::ExtU32;

    #[test]
    fn tick_timeout() {
        let mut now = MockInstant::now();
        assert_eq!(now.elapsed().as_ticks(), 0);
        MockInstant::add_time(10.nanos());
        assert_eq!(now.elapsed().as_ticks(), 10);
        MockInstant::add_time(1.millis());
        assert_eq!(now.elapsed().as_ticks(), 1_000_010);
        MockInstant::add_time(10.micros());
        let mut now2 = MockInstant::now();
        assert_eq!(now.elapsed().as_ticks(), 1_010_010);
        MockInstant::add_time(10.micros());
        assert_eq!(now2.elapsed().as_ticks(), 10_000);

        let mut t = TickTimeout::<MockInstant>::nanos(100);
        assert!(!t.timeout());
        MockInstant::add_time(10.nanos());
        assert!(!t.timeout());
        MockInstant::add_time(90.nanos());
        assert!(t.timeout());
        assert!(!t.timeout());
        MockInstant::add_time(100.nanos());
        assert!(t.timeout());

        MockInstant::add_time(90.nanos());
        assert!(!t.timeout());
        t.restart();
        MockInstant::add_time(90.nanos());
        assert!(!t.timeout());
        MockInstant::add_time(10.nanos());
        assert!(t.timeout());

        let mut t = TickTimeout::<MockInstant>::micros(100);
        assert!(!t.timeout());
        MockInstant::add_time(10.micros());
        assert!(!t.timeout());
        MockInstant::add_time(90.micros());
        assert!(t.timeout());
        assert!(!t.timeout());
        MockInstant::add_time(100.micros());
        assert!(t.timeout());

        MockInstant::add_time(90.micros());
        assert!(!t.timeout());
        t.restart();
        MockInstant::add_time(90.micros());
        assert!(!t.timeout());
        MockInstant::add_time(10.micros());
        assert!(t.timeout());

        let mut t = TickTimeout::<MockInstant>::millis(100);
        assert!(!t.timeout());
        MockInstant::add_time(10.millis());
        assert!(!t.timeout());
        MockInstant::add_time(90.millis());
        assert!(t.timeout());
        assert!(!t.timeout());
        MockInstant::add_time(100.millis());
        assert!(t.timeout());

        MockInstant::add_time(90.millis());
        assert!(!t.timeout());
        t.restart();
        MockInstant::add_time(90.millis());
        assert!(!t.timeout());
        MockInstant::add_time(10.millis());
        assert!(t.timeout());

        let mut count = 0;
        let dur = TickDuration::<MockInstant>::nanos(100);
        let t = MockInstant::now();
        assert!(t.timeout_with(&dur, || {
            MockInstant::add_time(10.nanos());
            count += 1;
            true
        }));
        assert_eq!(count, 10);

        let t = TickTimeout::<MockInstant>::micros(40_000_000);
        assert_eq!(t.timeout.as_ticks(), 40_000_000_000);

        let mut t = TickTimeout::<MockInstant>::millis(40_000);
        assert_eq!(t.timeout.as_ticks(), 40_000_000_000);

        assert!(!t.timeout());

        for _ in 0..40 {
            MockInstant::add_time(999.millis());
            assert!(!t.timeout());
        }
        MockInstant::add_time(100.millis());
        assert!(t.timeout());
        assert!(!t.timeout());

        for _ in 0..39 {
            MockInstant::add_time(999.millis());
            assert!(!t.timeout());
        }
        t.restart();
        for _ in 0..40 {
            MockInstant::add_time(999.millis());
            assert!(!t.timeout());
        }
        MockInstant::add_time(100.millis());
        assert!(t.timeout());

        let dur = TickDuration::<MockInstant>::micros(40_000_000);
        let t = TickTimeout::from(&dur);
        assert_eq!(t.timeout.as_ticks(), 40_000_000_000);

        let t = TickTimeout::new(dur);
        assert_eq!(t.timeout.as_ticks(), 40_000_000_000);
    }
}

#[cfg(test)]
mod tests_fugit {
    use core::ops::Div;
    use fugit::{
        ExtU32, ExtU32Ceil, KilohertzU32, MicrosDurationU32, MillisDurationU32, NanosDurationU64,
        RateExtU32,
    };

    #[test]
    fn duration_tick() {
        assert_eq!(1 / 1000, 0);
        assert_eq!(1_u32.div(1000), 0);
        assert_eq!(1_u32.div_ceil(1000), 1);

        let dur: MicrosDurationU32 = 1.micros();
        assert_eq!(dur.ticks(), 1);

        let dur: MicrosDurationU32 = 1.millis();
        assert_eq!(dur.ticks(), 1000);
        assert_eq!(dur.to_millis(), 1);

        let dur: MillisDurationU32 = 1.millis();
        assert_eq!(dur.ticks(), 1);
        assert_eq!(dur.to_micros(), 1000);

        let dur: MillisDurationU32 = 1.micros();
        assert_eq!(dur.ticks(), 0);

        let dur: MillisDurationU32 = 1.micros_at_least();
        assert_eq!(dur.ticks(), 1);

        let dur: MicrosDurationU32 = 1.micros();
        assert_eq!(dur.to_millis(), 0);
        let dur: MillisDurationU32 = dur.ticks().micros_at_least();
        assert_eq!(dur.ticks(), 1);

        let a = MicrosDurationU32::micros(100);
        let b = MicrosDurationU32::micros(99);
        assert!(b < a);

        let a = NanosDurationU64::micros(100);
        let b = NanosDurationU64::micros(101);
        assert!(b > a);
    }

    #[test]
    fn rate_tick() {
        let r: KilohertzU32 = 1.MHz();
        assert_eq!(r.raw(), 1_000);
        let f: u32 = r.to_Hz();
        assert_eq!(f, 1_000_000);
    }
}