use std::fmt;
use std::hash::Hash;
use std::str::FromStr;
pub trait EntityIdType:
Copy + Clone + Eq + Hash + fmt::Debug + fmt::Display + FromStr + Send + Sync + 'static
{
const ENTITY_NAME: &'static str;
fn new(id: u128) -> Self;
fn as_u128(&self) -> u128;
fn now_v7() -> Self;
fn nil() -> Self;
}
pub fn generate_v7_id() -> u128 {
uuid::Uuid::now_v7().as_u128()
}
#[macro_export]
macro_rules! define_entity_id {
($name:ident, $entity:literal) => {
#[doc = concat!("Typed entity ID for `", $entity, "` entities. Wraps a `u128` UUIDv7.")]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct $name(u128);
impl $crate::id::EntityIdType for $name {
const ENTITY_NAME: &'static str = $entity;
fn new(id: u128) -> Self {
Self(id)
}
fn as_u128(&self) -> u128 {
self.0
}
fn now_v7() -> Self {
Self($crate::id::generate_v7_id())
}
fn nil() -> Self {
Self(0)
}
}
impl ::std::fmt::Display for $name {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
write!(f, "{}:{:032x}", $entity, self.0)
}
}
impl ::std::str::FromStr for $name {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let hex = s.strip_prefix(concat!($entity, ":")).unwrap_or(s);
u128::from_str_radix(hex, 16)
.map(Self)
.map_err(|e| format!("invalid {}: {e}", $entity))
}
}
};
}
define_entity_id!(EventId, "event");