use std::{ fmt::{self, Debug}, hash::Hash, marker::PhantomData, }; pub trait IdKind: Debug + Copy + Clone + Hash + PartialEq + Eq + Default { fn tag() -> &'static str; } /// A generalized abstract identifier type of up to 2^32-1 entries. #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Default)] pub struct Id where T: IdKind { idx: u32, t: PhantomData, } impl Id where T: IdKind { fn new(n: u32) -> Self { Self { idx: n, t: PhantomData } } #[allow(dead_code)] pub fn as_u32(&self) -> u32 { self.idx } } impl fmt::Display for Id where T: IdKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}:{}", self.idx, T::tag()) } } pub struct IdStore where T: IdKind { last_idx: u32, t: PhantomData, } impl IdStore where T: IdKind { pub fn new() -> Self { Self { last_idx: 0, t: PhantomData } } pub fn fresh(&mut self) -> Id { let idx = self.last_idx; self.last_idx += 1; Id::new(idx) } } macro_rules! define_id_kind { ($name:ident) => { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Default)] pub struct $name; impl crate::identifier::IdKind for $name { fn tag() -> &'static str { stringify!($name) } } }; } pub(crate) use define_id_kind;