use std::fmt::{Debug, Formatter}; use std::mem::transmute; use std::sync::atomic::{AtomicU32, Ordering}; use crate::util::{gen_mask_64, BitMask, NumberExt}; static NEXT: AtomicU32 = AtomicU32::new(1); const ID_BITS: BitMask = BitMask::new(gen_mask_64!(32..=63)); const KIND_BITS: BitMask = BitMask::new(gen_mask_64!(0..=1)); #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] #[repr(u8)] pub enum Kind { Entity = 2, Component = 1, } /// Unique entity/component ID. #[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Uid { inner: u64, } impl Uid { /// Returns a new unique entity/component ID. pub fn new_unique(kind: Kind) -> Self { let id = NEXT.fetch_add(1, Ordering::Relaxed); Self { inner: ID_BITS.field_prep(id as u64) | KIND_BITS.field_prep(kind as u64), } } #[must_use] pub fn id(&self) -> u32 { self.inner.field_get(ID_BITS) as u32 } #[must_use] pub fn kind(&self) -> Kind { // SAFETY: The kind bits cannot be invalid since they are set using the Kind enum // in the new_unique function unsafe { transmute(self.inner.field_get(KIND_BITS) as u8) } } } impl Debug for Uid { fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result { formatter .debug_struct("Uid") .field("id", &self.id()) .field("kind", &self.kind()) .finish_non_exhaustive() } }