//! Canonical ID newtypes used across the Prometeu workspace. //! Keep this crate low-level and independent from higher layers. macro_rules! define_id { ($name:ident) => { #[repr(transparent)] #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, serde::Serialize, serde::Deserialize)] pub struct $name(pub u32); impl $name { pub const INVALID: $name = $name(u32::MAX); #[inline] pub const fn as_u32(self) -> u32 { self.0 } // Temporary helper for places that still index Vec/slots by usize #[inline] pub const fn as_usize(self) -> usize { self.0 as usize } } impl From for $name { #[inline] fn from(value: u32) -> Self { Self(value) } } impl From<$name> for u32 { #[inline] fn from(value: $name) -> Self { value.0 } } }; } define_id!(FileId); define_id!(NodeId); define_id!(NameId); define_id!(SymbolId); define_id!(TypeId); define_id!(ModuleId); define_id!(ProjectId); #[cfg(test)] mod tests { use super::*; use std::collections::HashMap; use std::mem::size_of; #[test] fn ids_are_repr_transparent_and_hashable() { assert_eq!(size_of::(), 4); assert_eq!(size_of::(), 4); assert_eq!(size_of::(), 4); assert_eq!(size_of::(), 4); assert_eq!(size_of::(), 4); assert_eq!(size_of::(), 4); assert_eq!(size_of::(), 4); // Hash/Eq usage let mut m: HashMap = HashMap::new(); m.insert(SymbolId(1), "one"); assert_eq!(m.get(&SymbolId(1)).copied(), Some("one")); } }