use core::{
cmp::Ordering,
ops::{Add, AddAssign, Sub, SubAssign},
};
use bevy::prelude::*;
use postcard::experimental::max_size::MaxSize;
use serde::{Deserialize, Serialize};
#[derive(
Reflect, Debug, Default, Serialize, Deserialize, Eq, Hash, PartialEq, MaxSize, Clone, Copy,
)]
pub struct RepliconTick(u32);
impl RepliconTick {
pub const MAX_NEWER_DISTANCE: u32 = u32::MAX / 2;
#[inline]
pub fn new(value: u32) -> Self {
Self(value)
}
#[inline]
pub fn get(self) -> u32 {
self.0
}
pub fn wrapping_cmp(self, other: Self) -> Ordering {
let distance = self.0.wrapping_sub(other.0);
if distance == 0 {
Ordering::Equal
} else if distance <= Self::MAX_NEWER_DISTANCE {
Ordering::Greater
} else {
Ordering::Less
}
}
pub fn is_newer_or_eq(self, other: Self) -> bool {
self.wrapping_cmp(other).is_ge()
}
pub fn is_newer(self, other: Self) -> bool {
self.wrapping_cmp(other).is_gt()
}
pub fn is_older(self, other: Self) -> bool {
self.wrapping_cmp(other).is_lt()
}
pub fn is_older_or_eq(self, other: Self) -> bool {
self.wrapping_cmp(other).is_le()
}
}
impl Add<u32> for RepliconTick {
type Output = Self;
fn add(self, rhs: u32) -> Self::Output {
Self(self.0.wrapping_add(rhs))
}
}
impl AddAssign<u32> for RepliconTick {
fn add_assign(&mut self, rhs: u32) {
self.0 = self.0.wrapping_add(rhs)
}
}
impl Sub for RepliconTick {
type Output = u32;
fn sub(self, rhs: Self) -> Self::Output {
self.0.wrapping_sub(rhs.0)
}
}
impl Sub<u32> for RepliconTick {
type Output = Self;
fn sub(self, rhs: u32) -> Self::Output {
Self(self.0.wrapping_sub(rhs))
}
}
impl SubAssign<u32> for RepliconTick {
fn sub_assign(&mut self, rhs: u32) {
self.0 = self.0.wrapping_sub(rhs);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn tick_comparison() {
assert_eq!(RepliconTick::new(0), RepliconTick::new(0));
assert!(RepliconTick::new(0).is_newer_or_eq(RepliconTick::new(0)));
assert!(RepliconTick::new(0).is_older_or_eq(RepliconTick::new(0)));
assert!(RepliconTick::new(1).is_newer(RepliconTick::new(0)));
assert!(RepliconTick::new(1).is_newer_or_eq(RepliconTick::new(0)));
assert!(RepliconTick::new(u32::MAX).is_older(RepliconTick::new(0)));
assert!(RepliconTick::new(u32::MAX).is_older_or_eq(RepliconTick::new(0)));
}
}