ztimer 0.1.2

A block-based, non-circular double-linked list implementation for Rust.
Documentation
// Copyright 2024 Lorby Bi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::{
    ops::{Add, AddAssign, Mul, Sub},
    time::Duration,
};

pub(super) const DURATION_PER_TICK: Duration = Duration::from_micros(500); // 0.5 ms
pub(super) const TICKS_PER_SECOND: Interval =
    Interval((Duration::from_secs(1).as_micros() / DURATION_PER_TICK.as_micros()) as i64);

#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
pub struct Tick(pub(super) u64);
impl From<u64> for Tick {
    fn from(n: u64) -> Self {
        Tick(n)
    }
}
impl AddAssign<u64> for Tick {
    fn add_assign(&mut self, rhs: u64) {
        self.0 = self.0.wrapping_add(rhs);
    }
}

impl Tick {
    // Return the tick that is `interval` away from this tick.
    pub(super) fn until(&self, interval: Interval) -> Tick {
        assert!(interval.0 >= 0, "Negative interval");
        Tick(self.0.wrapping_add_signed(interval.0))
    }

    pub(in super::super) fn to_u64(&self) -> u64 {
        self.0
    }

    // Return the interval since the given tick until this tick.
    pub(super) fn since(&self, tick: Tick) -> Interval {
        assert!(self.0 >= tick.0, "tick is behind");
        Interval(self.0.wrapping_sub(tick.0) as i64)
    }
}
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
pub(super) struct Interval(pub(super) i64);
impl From<Duration> for Interval {
    fn from(duration: Duration) -> Self {
        Interval((duration.as_micros() / DURATION_PER_TICK.as_micros()) as i64)
    }
}
impl From<i64> for Interval {
    fn from(n: i64) -> Self {
        Interval(n)
    }
}

impl Interval {
    pub(in super::super) fn to_i64(&self) -> i64 {
        self.0
    }
}
impl Add for Interval {
    type Output = Self;
    fn add(self, rhs: Self) -> Self::Output {
        Interval(self.0.wrapping_add(rhs.0))
    }
}
impl Sub for Interval {
    type Output = Self;
    fn sub(self, rhs: Self) -> Self::Output {
        Interval(self.0.wrapping_sub(rhs.0))
    }
}
impl Mul<u32> for Interval {
    type Output = Self;
    fn mul(self, rhs: u32) -> Self::Output {
        Interval(self.0.wrapping_mul(rhs as i64))
    }
}
impl Mul<i32> for Interval {
    type Output = Self;
    fn mul(self, rhs: i32) -> Self::Output {
        Interval(self.0.wrapping_mul(rhs as i64))
    }
}
impl Mul<i64> for Interval {
    type Output = Self;
    fn mul(self, rhs: i64) -> Self::Output {
        Interval(self.0.wrapping_mul(rhs as i64))
    }
}
impl Mul<u64> for Interval {
    type Output = Self;
    fn mul(self, rhs: u64) -> Self::Output {
        Interval(self.0.wrapping_mul(rhs as i64))
    }
}
#[cfg(test)]
mod tests {
    use super::*;
    extern crate env_logger;
    use env_logger::{Builder, Env};
    use std::sync::Once;

    static INIT: Once = Once::new();

    fn initialize() {
        INIT.call_once(|| {
            let _ = Builder::from_env(Env::default().default_filter_or("error")).try_init();
        });
    }
    #[test]
    fn test_tick_from_u64() {
        let tick = Tick::from(10);
        assert_eq!(tick.0, 10);
    }

    #[test]
    fn test_tick_until() {
        let tick = Tick(5);
        let interval = Interval(2);
        let result = tick.until(interval);
        assert_eq!(result.0, 7);
        assert_eq!(tick.0, 5);
    }
    #[test]
    fn test_tick_add_assign() {
        let mut tick = Tick(5);
        tick += 2;
        assert_eq!(tick.0, 7);
    }

    #[test]
    #[should_panic(expected = "Negative interval")]
    fn test_tick_until_negative_interval() {
        let tick = Tick(5);
        let interval = Interval(-2);
        tick.until(interval);
    }

    #[test]
    fn test_tick_since() {
        let tick1 = Tick(10);
        let tick2 = Tick(5);
        let result = tick1.since(tick2);
        assert_eq!(result.0, 5);
        assert_eq!(tick1.0, 10);
    }

    #[test]
    #[should_panic(expected = "tick is behind")]
    fn test_tick_since_tick_behind() {
        let tick1 = Tick(5);
        let tick2 = Tick(10);
        tick1.since(tick2);
    }

    #[test]
    fn test_interval_from_duration() {
        let duration = Duration::from_secs(2);
        let result = Interval::from(duration);
        assert_eq!(result.0, 4000);
    }

    #[test]
    fn test_interval_from_i64() {
        let interval = Interval::from(100);
        assert_eq!(interval.0, 100);
    }

    #[test]
    fn test_interval_add() {
        let interval1 = Interval(5);
        let interval2 = Interval(3);
        let result = interval1 + interval2;
        assert_eq!(result.0, 8);
    }

    #[test]
    fn test_interval_sub() {
        let interval1 = Interval(10);
        let interval2 = Interval(3);
        let result = interval1 - interval2;
        assert_eq!(result.0, 7);
    }
}