use core::num::NonZeroU64;
use serde::{Deserialize, Serialize};
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct InstanceId(NonZeroU64);
impl InstanceId {
#[inline]
pub const fn new(v: u64) -> Option<Self> {
match NonZeroU64::new(v) {
Some(n) => Some(Self(n)),
None => None,
}
}
#[inline]
pub const fn get(self) -> u64 {
self.0.get()
}
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct EntityId(NonZeroU64);
impl EntityId {
#[inline]
pub const fn new(v: u64) -> Option<Self> {
match NonZeroU64::new(v) {
Some(n) => Some(Self(n)),
None => None,
}
}
#[inline]
pub const fn get(self) -> u64 {
self.0.get()
}
}
#[derive(
Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default, Serialize, Deserialize,
)]
#[serde(transparent)]
pub struct Tick(pub u64);
impl Tick {
pub const ZERO: Tick = Tick(0);
#[inline]
pub const fn advance(self, delta: u64) -> Tick {
Tick(self.0.saturating_add(delta))
}
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct TypeCode(pub u32);
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct RouteId(pub u32);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn instance_id_zero_is_unrepresentable() {
assert!(InstanceId::new(0).is_none());
}
#[test]
fn instance_id_nonzero_roundtrip() {
let id = InstanceId::new(42).expect("42 is non-zero");
assert_eq!(id.get(), 42);
}
#[test]
fn entity_id_zero_is_unrepresentable() {
assert!(EntityId::new(0).is_none());
}
#[test]
fn entity_id_nonzero_roundtrip() {
let id = EntityId::new(u64::MAX).expect("max is non-zero");
assert_eq!(id.get(), u64::MAX);
}
#[test]
fn tick_advance_saturates_without_wrapping() {
assert_eq!(Tick::ZERO.advance(100).0, 100);
assert_eq!(Tick(u64::MAX).advance(1).0, u64::MAX);
assert_eq!(Tick(u64::MAX - 5).advance(10).0, u64::MAX);
}
#[test]
fn type_code_and_route_id_are_totally_ordered() {
assert!(TypeCode(1) < TypeCode(2));
assert!(RouteId(10) > RouteId(5));
}
#[test]
fn ids_are_copy_and_eq() {
fn assert_copy<T: Copy>() {}
fn assert_eq<T: Eq>() {}
fn assert_ord<T: Ord>() {}
fn assert_hash<T: core::hash::Hash>() {}
assert_copy::<InstanceId>();
assert_copy::<EntityId>();
assert_copy::<Tick>();
assert_copy::<TypeCode>();
assert_copy::<RouteId>();
assert_eq::<InstanceId>();
assert_ord::<InstanceId>();
assert_hash::<InstanceId>();
}
}