use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use crate::error::EcsError;
use crate::index::{DataIndex, MAX_DATA_INDEX};
use crate::traits::{Archetype, EntityKey};
use crate::version::{VersionArchetype, VersionSlot};
pub type ArchetypeId = u8;
pub(crate) const ARCHETYPE_ID_BITS: u32 = ArchetypeId::BITS;
pub struct Entity<A: Archetype> {
inner: EntityAny,
_type: PhantomData<fn() -> A>,
}
pub struct EntityRaw<A: Archetype> {
inner: EntityRawAny,
_type: PhantomData<fn() -> A>,
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct EntityAny {
key: u32, version: VersionSlot,
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct EntityRawAny {
key: u32, version: VersionArchetype,
}
impl<A: Archetype> Entity<A> {
#[inline(always)]
pub(crate) fn new(
slot_index: DataIndex, version: VersionSlot,
) -> Self {
Self {
inner: EntityAny::new(slot_index, A::ARCHETYPE_ID, version),
_type: PhantomData,
}
}
#[inline(always)]
pub(crate) fn slot_index(&self) -> DataIndex {
self.inner.slot_index()
}
#[inline(always)]
pub(crate) fn version(&self) -> VersionSlot {
self.inner.version()
}
#[inline(always)]
pub fn from_any(entity: EntityAny) -> Self {
if entity.archetype_id() != A::ARCHETYPE_ID {
panic!("invalid entity conversion");
}
Self {
inner: entity,
_type: PhantomData,
}
}
#[inline(always)]
pub fn from_any_unchecked(entity: EntityAny) -> Self {
debug_assert!(entity.archetype_id() == A::ARCHETYPE_ID);
Self {
inner: entity,
_type: PhantomData,
}
}
#[inline(always)]
pub fn into_any(self) -> EntityAny {
self.inner
}
#[inline(always)]
pub const fn archetype_id(self) -> ArchetypeId {
A::ARCHETYPE_ID
}
}
impl EntityAny {
#[inline(always)]
pub(crate) fn new(
slot_index: DataIndex, archetype_id: ArchetypeId,
version: VersionSlot,
) -> Self {
let archetype_id: u32 = archetype_id.into();
let key = (slot_index.get() << ARCHETYPE_ID_BITS) | archetype_id;
Self { key, version }
}
#[inline(always)]
pub(crate) fn slot_index(&self) -> DataIndex {
unsafe {
debug_assert!(self.key >> ARCHETYPE_ID_BITS <= MAX_DATA_INDEX);
DataIndex::new_unchecked(self.key >> ARCHETYPE_ID_BITS)
}
}
#[inline(always)]
pub const fn archetype_id(self) -> ArchetypeId {
self.key as ArchetypeId }
#[inline(always)]
pub(crate) const fn version(&self) -> VersionSlot {
self.version
}
#[inline(always)]
pub fn into_any(self) -> EntityAny {
self
}
}
impl<A: Archetype> EntityRaw<A> {
#[inline(always)]
pub(crate) fn new(
dense_index: DataIndex, version: VersionArchetype,
) -> Self {
Self {
inner: EntityRawAny::new(dense_index, A::ARCHETYPE_ID, version),
_type: PhantomData,
}
}
#[inline(always)]
pub(crate) fn dense_index(&self) -> DataIndex {
self.inner.dense_index()
}
#[inline(always)]
pub(crate) fn version(&self) -> VersionArchetype {
self.inner.version()
}
#[inline(always)]
pub fn from_any(entity: EntityRawAny) -> Self {
if entity.archetype_id() != A::ARCHETYPE_ID {
panic!("invalid entity conversion");
}
Self {
inner: entity,
_type: PhantomData,
}
}
#[inline(always)]
pub fn from_any_unchecked(entity: EntityRawAny) -> Self {
debug_assert!(entity.archetype_id() == A::ARCHETYPE_ID);
Self {
inner: entity,
_type: PhantomData,
}
}
#[inline(always)]
pub fn into_any(self) -> EntityRawAny {
self.inner
}
#[inline(always)]
pub const fn archetype_id(self) -> ArchetypeId {
A::ARCHETYPE_ID
}
}
impl EntityRawAny {
#[inline(always)]
pub(crate) fn new(
dense_index: DataIndex, archetype_id: ArchetypeId,
version: VersionArchetype,
) -> Self {
let archetype_id: u32 = archetype_id.into();
let key = (dense_index.get() << ARCHETYPE_ID_BITS) | archetype_id;
Self { key, version }
}
#[inline(always)]
pub(crate) fn dense_index(&self) -> DataIndex {
unsafe {
debug_assert!(self.key >> ARCHETYPE_ID_BITS <= MAX_DATA_INDEX);
DataIndex::new_unchecked(self.key >> ARCHETYPE_ID_BITS)
}
}
#[inline(always)]
pub const fn archetype_id(self) -> ArchetypeId {
self.key as ArchetypeId }
#[inline(always)]
pub(crate) const fn version(&self) -> VersionArchetype {
self.version
}
#[inline(always)]
pub fn into_any(self) -> EntityRawAny {
self
}
}
impl Hash for EntityAny {
#[inline(always)]
fn hash<H: Hasher>(&self, state: &mut H) {
let index: u64 = self.key.into();
let version: u64 = self.version.get().get().into();
let combined = (index << 32) | version;
combined.hash(state);
}
}
impl Hash for EntityRawAny {
#[inline(always)]
fn hash<H: Hasher>(&self, state: &mut H) {
let index: u64 = self.key.into();
let version: u64 = self.version.get().get().into();
let combined = (index << 32) | version;
combined.hash(state);
}
}
impl<A: Archetype> From<Entity<A>> for EntityAny {
#[inline(always)]
fn from(entity: Entity<A>) -> Self {
entity.inner
}
}
impl<A: Archetype> From<EntityRaw<A>> for EntityRawAny {
#[inline(always)]
fn from(entity: EntityRaw<A>) -> Self {
entity.inner
}
}
impl<A: Archetype> TryFrom<EntityAny> for Entity<A> {
type Error = EcsError;
#[inline(always)]
fn try_from(entity: EntityAny) -> Result<Self, Self::Error> {
if entity.archetype_id() == A::ARCHETYPE_ID {
Ok(Self {
inner: entity,
_type: PhantomData,
})
} else {
Err(EcsError::InvalidEntityType)
}
}
}
impl<A: Archetype> TryFrom<EntityRawAny> for EntityRaw<A> {
type Error = EcsError;
#[inline(always)]
fn try_from(entity: EntityRawAny) -> Result<Self, Self::Error> {
if entity.archetype_id() == A::ARCHETYPE_ID {
Ok(Self {
inner: entity,
_type: PhantomData,
})
} else {
Err(EcsError::InvalidEntityType)
}
}
}
impl<A: Archetype> Clone for Entity<A> {
#[inline(always)]
fn clone(&self) -> Entity<A> {
Entity {
inner: self.inner,
_type: PhantomData,
}
}
}
impl<A: Archetype> Clone for EntityRaw<A> {
#[inline(always)]
fn clone(&self) -> EntityRaw<A> {
EntityRaw {
inner: self.inner,
_type: PhantomData,
}
}
}
impl<A: Archetype> PartialEq for Entity<A> {
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner
}
}
impl<A: Archetype> PartialEq for EntityRaw<A> {
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner
}
}
impl<A: Archetype> Hash for Entity<A> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.inner.hash(state)
}
}
impl<A: Archetype> Hash for EntityRaw<A> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.inner.hash(state)
}
}
impl<A: Archetype> Copy for Entity<A> {}
impl<A: Archetype> Copy for EntityRaw<A> {}
impl<A: Archetype> Eq for Entity<A> {}
impl<A: Archetype> Eq for EntityRaw<A> {}
impl<A: Archetype> EntityKey for Entity<A> {
type DestroyOutput = Option<A::Components>;
}
impl<A: Archetype> EntityKey for EntityRaw<A> {
type DestroyOutput = Option<A::Components>;
}
impl EntityKey for EntityAny {
type DestroyOutput = bool;
}
impl EntityKey for EntityRawAny {
type DestroyOutput = bool;
}
#[doc(hidden)]
pub mod __internal {
use super::*;
#[doc(hidden)]
#[inline(always)]
pub fn new_entity_raw<A: Archetype>(index: usize, version: VersionArchetype) -> EntityRaw<A> {
EntityRaw::new(DataIndex::new_usize(index).unwrap(), version)
}
}