#[cfg(feature = "serde1")]
mod serde;
use core::num::NonZeroU64;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct EntityId(pub(super) NonZeroU64);
impl Default for EntityId {
fn default() -> Self {
Self::dead()
}
}
impl EntityId {
const GEN_LEN: u64 = 16;
const INDEX_LEN: u64 = 64 - Self::GEN_LEN;
const INDEX_MASK: u64 = !(!0 << Self::INDEX_LEN);
const GEN_MASK: u64 = !(!0 >> Self::GEN_LEN);
const MAX_GEN: u16 = u16::MAX - 1;
#[inline]
pub fn index(self) -> u64 {
(self.0.get() & Self::INDEX_MASK) - 1
}
#[inline]
pub fn uindex(self) -> usize {
self.index() as usize
}
#[inline]
pub(crate) fn set_index(&mut self, index: u64) {
assert!(index < Self::INDEX_MASK);
self.0 =
unsafe { NonZeroU64::new_unchecked((index + 1) | (self.0.get() & !Self::INDEX_MASK)) }
}
#[inline]
pub fn gen(self) -> u16 {
((self.0.get() & Self::GEN_MASK) >> Self::INDEX_LEN) as u16
}
#[inline]
pub(super) fn bump_gen(&mut self) -> Result<(), ()> {
if self.gen() < Self::MAX_GEN - 1 {
self.0 = unsafe {
NonZeroU64::new_unchecked(
(self.0.get() & !Self::GEN_MASK)
| (((self.gen() + 1) as u64) << Self::INDEX_LEN),
)
};
Ok(())
} else {
Err(())
}
}
#[inline]
pub(crate) fn new(index: u64) -> Self {
assert!(index < Self::INDEX_MASK);
EntityId(unsafe { NonZeroU64::new_unchecked(index + 1) })
}
#[inline]
pub(crate) const fn new_from_parts(index: u64, gen: u16) -> Self {
assert!(index < Self::INDEX_MASK);
EntityId(unsafe {
NonZeroU64::new_unchecked((index + 1) | ((gen as u64) << Self::INDEX_LEN))
})
}
#[inline]
pub const fn new_from_index_and_gen(index: u64, gen: u16) -> Self {
EntityId::new_from_parts(index, gen)
}
#[cfg(test)]
pub(crate) fn zero() -> Self {
EntityId(NonZeroU64::new(1).unwrap())
}
#[inline]
pub fn dead() -> Self {
EntityId(unsafe { NonZeroU64::new_unchecked(!0) })
}
#[inline]
pub(crate) fn bucket(self) -> usize {
self.uindex() / crate::sparse_set::BUCKET_SIZE
}
#[inline]
pub(crate) fn bucket_index(self) -> usize {
self.uindex() % crate::sparse_set::BUCKET_SIZE
}
#[inline]
pub(crate) fn max_index() -> u64 {
Self::INDEX_MASK - 1
}
#[inline]
pub(crate) const fn max_gen() -> u16 {
Self::MAX_GEN
}
#[inline]
pub(crate) fn is_dead(&self) -> bool {
(self.0.get() & Self::GEN_MASK) == Self::GEN_MASK
}
#[inline]
pub(crate) fn copy_index(&mut self, other: EntityId) {
unsafe {
self.0 = NonZeroU64::new_unchecked(
(self.0.get() & !Self::INDEX_MASK) | (other.0.get() & Self::INDEX_MASK),
);
}
}
#[inline]
pub(crate) fn copy_gen(&mut self, other: EntityId) {
unsafe {
self.0 = NonZeroU64::new_unchecked(
(self.0.get() & !Self::GEN_MASK) | (other.0.get() & Self::GEN_MASK),
);
}
}
#[inline]
pub(crate) fn copy_index_gen(&mut self, other: EntityId) {
unsafe {
self.0 = NonZeroU64::new_unchecked(self.0.get() | other.0.get());
}
}
#[inline]
pub fn inner(self) -> u64 {
self.0.get()
}
#[inline]
pub fn from_inner(inner: u64) -> Option<EntityId> {
Some(EntityId(NonZeroU64::new(inner)?))
}
}
impl core::fmt::Debug for EntityId {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
if *self == EntityId::dead() {
f.write_str("EId(dead)")
} else {
write!(f, "EId({}.{})", self.index(), self.gen())
}
}
}
#[test]
fn entity_id() {
let mut entity_id = EntityId::new(0);
assert_eq!(entity_id.index(), 0);
assert_eq!(entity_id.gen(), 0);
entity_id.set_index(701);
assert_eq!(entity_id.index(), 701);
assert_eq!(entity_id.gen(), 0);
entity_id.bump_gen().unwrap();
entity_id.bump_gen().unwrap();
entity_id.bump_gen().unwrap();
assert_eq!(entity_id.index(), 701);
assert_eq!(entity_id.gen(), 3);
entity_id.set_index(554);
assert_eq!(entity_id.index(), 554);
assert_eq!(entity_id.gen(), 3);
}