use std::fmt;
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
pub struct Id<T> {
value: u64,
_marker: PhantomData<fn() -> T>,
}
impl<T> Id<T> {
pub const fn new(value: u64) -> Self {
Self {
value,
_marker: PhantomData,
}
}
pub const fn value(&self) -> u64 {
self.value
}
}
impl<T> Clone for Id<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for Id<T> {}
impl<T> PartialEq for Id<T> {
fn eq(&self, other: &Self) -> bool {
self.value == other.value
}
}
impl<T> Eq for Id<T> {}
impl<T> Hash for Id<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.value.hash(state);
}
}
impl<T> fmt::Debug for Id<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Id").field(&self.value).finish()
}
}
impl<T> fmt::Display for Id<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.value)
}
}
#[cfg(test)]
mod tests {
use super::*;
struct Route;
struct Interface;
#[test]
fn same_value_is_equal_within_the_same_domain() {
assert_eq!(Id::<Route>::new(1), Id::<Route>::new(1));
assert_ne!(Id::<Route>::new(1), Id::<Route>::new(2));
}
#[test]
fn different_domains_are_distinct_types() {
let route_id = Id::<Route>::new(1);
let interface_id = Id::<Interface>::new(1);
assert_eq!(route_id.value(), interface_id.value());
}
#[test]
fn value_round_trips() {
assert_eq!(Id::<Route>::new(42).value(), 42);
}
}