use std::{
ops::{Add, AddAssign, Mul, Sub},
time::Duration,
};
pub(super) const DURATION_PER_TICK: Duration = Duration::from_micros(500); 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 {
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
}
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);
}
}