use super::component::{ComponentKey, Components};
use my_utils::{
ds::{BorrowResult, RawGetter, TypeInfo},
With,
};
use std::{any::TypeId, fmt, mem, mem::MaybeUninit, ops::Deref, ptr::NonNull, sync::Arc};
pub trait Entity: Components + Send + 'static {
type Ref<'cont>;
type Mut<'cont>;
const OFFSETS_BY_FIELD_INDEX: &'static [usize];
fn field_to_column_index(fi: usize) -> usize;
fn column_to_field_index(ci: usize) -> usize {
unsafe {
(0..Self::num_components())
.find(|&fi| Self::field_to_column_index(fi) == ci)
.unwrap_unchecked()
}
}
fn get_ref_from<Cont: ContainEntity + ?Sized>(cont: &Cont, vi: usize) -> Self::Ref<'_>;
fn get_mut_from<Cont: ContainEntity + ?Sized>(cont: &mut Cont, vi: usize) -> Self::Mut<'_>;
#[doc(hidden)]
fn key() -> EntityKey {
let ckeys: Arc<[ComponentKey]> = (0..Self::num_components())
.map(|ci| {
let fi = Self::column_to_field_index(ci);
Self::keys().as_ref()[fi]
})
.collect();
EntityKey::Ckeys(ckeys)
}
fn num_components() -> usize {
Self::LEN
}
fn component_ptr(&self, fi: usize) -> NonNull<u8> {
let base_ptr = (self as *const Self as *const u8).cast_mut();
unsafe {
let ptr = base_ptr.add(Self::OFFSETS_BY_FIELD_INDEX[fi]);
NonNull::new_unchecked(ptr)
}
}
fn register_to<Cont: ContainEntity + ?Sized>(cont: &mut Cont) {
assert_eq!(cont.num_columns(), 0);
for ci in 0..Self::num_components() {
let fi = Self::column_to_field_index(ci);
let tinfo = Self::infos().as_ref()[fi];
cont.add_column(tinfo);
}
}
fn move_to<Cont: ContainEntity + ?Sized>(self, cont: &mut Cont) -> usize
where
Self: Sized,
{
cont.begin_add_row();
for fi in 0..Self::num_components() {
let ci = Self::field_to_column_index(fi);
unsafe { cont.add_value(ci, self.component_ptr(fi)) };
}
#[allow(clippy::forget_non_drop)]
mem::forget(self);
unsafe { cont.end_add_row() }
}
fn take_from<Cont: ContainEntity + ?Sized>(cont: &mut Cont, vi: usize) -> Self
where
Self: Sized,
{
assert!(vi < cont.len());
let mut this: MaybeUninit<Self> = MaybeUninit::uninit();
let base_ptr = this.as_mut_ptr() as *mut u8;
unsafe {
cont.begin_remove_row_by_value_index(vi);
for fi in 0..Self::num_components() {
let comp_ptr = base_ptr.add(Self::OFFSETS_BY_FIELD_INDEX[fi]);
let comp_ptr = NonNull::new_unchecked(comp_ptr);
let ci = Self::field_to_column_index(fi);
cont.remove_value_by_value_index(ci, vi, comp_ptr);
}
cont.end_remove_row_by_value_index(vi);
this.assume_init()
}
}
}
#[allow(clippy::len_without_is_empty)]
pub trait ContainEntity: RegisterComponent + BorrowComponent + AddEntity {
fn create_twin(&self) -> Box<dyn ContainEntity>;
fn get_item_mut(&mut self, ci: usize, ri: usize) -> Option<NonNull<u8>>;
fn len(&self) -> usize;
fn capacity(&self) -> usize;
fn reserve(&mut self, additional: usize);
fn shrink_to_fit(&mut self);
unsafe fn resize_column(&mut self, ci: usize, new_len: usize, val_ptr: NonNull<u8>);
}
pub trait RegisterComponent {
fn add_column(&mut self, tinfo: TypeInfo) -> Option<usize>;
fn remove_column(&mut self, ci: usize) -> Option<TypeInfo>;
fn get_column_index(&self, ty: &TypeId) -> Option<usize>;
fn get_column_info(&self, ci: usize) -> Option<&TypeInfo>;
fn num_columns(&self) -> usize;
fn contains_column(&self, ty: &TypeId) -> bool {
self.get_column_index(ty).is_some()
}
}
pub trait BorrowComponent {
fn borrow_column(&self, ci: usize) -> BorrowResult<RawGetter>;
fn borrow_column_mut(&mut self, ci: usize) -> BorrowResult<RawGetter>;
unsafe fn get_column(&self, ci: usize) -> Option<NonNull<u8>>;
}
pub trait AddEntity: RegisterComponent {
fn to_value_index(&self, ri: usize) -> Option<usize>;
fn begin_add_row(&mut self);
unsafe fn add_value(&mut self, ci: usize, val_ptr: NonNull<u8>);
unsafe fn end_add_row(&mut self) -> usize;
fn value_ptr_by_value_index(&self, ci: usize, vi: usize) -> Option<NonNull<u8>>;
fn remove_row(&mut self, ri: usize) -> bool {
if let Some(vi) = self.to_value_index(ri) {
self.remove_row_by_value_index(vi);
true
} else {
false
}
}
fn remove_row_by_value_index(&mut self, vi: usize) {
unsafe {
self.begin_remove_row_by_value_index(vi);
for ci in 0..self.num_columns() {
self.drop_value_by_value_index(ci, vi);
}
self.end_remove_row_by_value_index(vi);
}
}
unsafe fn begin_remove_row_by_value_index(&mut self, vi: usize);
unsafe fn remove_value_by_value_index(&mut self, ci: usize, vi: usize, buf: NonNull<u8>);
unsafe fn drop_value_by_value_index(&mut self, ci: usize, vi: usize);
unsafe fn forget_value_by_value_index(&mut self, ci: usize, vi: usize);
unsafe fn end_remove_row_by_value_index(&mut self, vi: usize);
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct EntityId {
ei: EntityIndex,
ri: usize,
}
impl EntityId {
pub const fn new(ei: EntityIndex, ri: usize) -> Self {
Self { ei, ri }
}
pub const fn container_index(&self) -> EntityIndex {
self.ei
}
pub const fn row_index(&self) -> usize {
self.ri
}
}
impl fmt::Display for EntityId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({}, {})", self.ei.index(), self.ri)
}
}
impl fmt::Debug for EntityId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("EntityId")
.field("gen", &self.ei.generation())
.field("ei", &self.ei.index())
.field("ri", &self.ri)
.finish()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum EntityKey {
Ckeys(Arc<[ComponentKey]>),
Index(EntityIndex),
Name(EntityName),
}
my_utils::impl_from_for_enum!("outer" = EntityKey; "var" = Ckeys; "inner" = Arc<[ComponentKey]>);
my_utils::impl_from_for_enum!("outer" = EntityKey; "var" = Index; "inner" = EntityIndex);
my_utils::impl_from_for_enum!("outer" = EntityKey; "var" = Name; "inner" = EntityName);
impl EntityKey {
pub(crate) fn index(&self) -> &EntityIndex {
self.try_into().unwrap()
}
pub(crate) fn get_ref(&self) -> EntityKeyRef<'_> {
match self {
Self::Index(ei) => EntityKeyRef::Index(ei),
Self::Ckeys(ckeys) => EntityKeyRef::Ckeys(ckeys),
Self::Name(name) => EntityKeyRef::Name(name),
}
}
}
impl<'r> From<&'r EntityKey> for EntityKeyRef<'r> {
fn from(value: &'r EntityKey) -> Self {
value.get_ref()
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) enum EntityKeyRef<'r> {
Ckeys(&'r [ComponentKey]),
Index(&'r EntityIndex),
Name(&'r str),
}
my_utils::impl_from_for_enum!(
"lifetimes" = 'r;
"outer" = EntityKeyRef; "var" = Ckeys; "inner" = &'r [ComponentKey]
);
my_utils::impl_from_for_enum!(
"lifetimes" = 'r;
"outer" = EntityKeyRef; "var" = Index; "inner" = &'r EntityIndex
);
my_utils::impl_from_for_enum!(
"lifetimes" = 'r;
"outer" = EntityKeyRef; "var" = Name; "inner" = &'r str
);
#[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
#[repr(transparent)]
pub struct EntityIndex(With<usize, u64>);
impl EntityIndex {
const DUMMY: Self = Self(With::new(usize::MAX, u64::MAX));
pub(crate) const fn new(index: With<usize, u64>) -> Self {
Self(index)
}
pub(crate) const fn dummy() -> Self {
Self::DUMMY
}
pub fn index(&self) -> usize {
*self.0
}
pub fn generation(&self) -> u64 {
*self.0.get_back()
}
}
impl Default for EntityIndex {
fn default() -> Self {
Self::dummy()
}
}
impl fmt::Display for EntityIndex {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
#[derive(Hash, PartialEq, Eq, Clone, Debug)]
#[repr(transparent)]
pub struct EntityName(Arc<str>);
impl EntityName {
pub const fn new(name: Arc<str>) -> Self {
Self(name)
}
}
impl Deref for EntityName {
type Target = str;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::borrow::Borrow<str> for EntityName {
fn borrow(&self) -> &str {
self
}
}
impl fmt::Display for EntityName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub(crate) enum EntityKeyKind {
Index,
Ckeys,
Name,
}
impl From<&EntityKey> for EntityKeyKind {
fn from(value: &EntityKey) -> Self {
match value {
EntityKey::Index(..) => Self::Index,
EntityKey::Ckeys(..) => Self::Ckeys,
EntityKey::Name(..) => Self::Name,
}
}
}
#[derive(Eq)]
pub struct EntityTag {
index: EntityIndex,
name: Option<EntityName>,
ckeys: Arc<[ComponentKey]>,
cnames: Box<[&'static str]>,
}
impl fmt::Debug for EntityTag {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("EntityTag")
.field("index", &self.index())
.field("name", &self.get_name())
.field("ckeys", &self.get_component_keys())
.field("cnames", &self.get_component_names())
.finish()
}
}
impl EntityTag {
pub(crate) fn new(
index: EntityIndex,
name: Option<EntityName>,
ckeys: Arc<[ComponentKey]>,
cnames: Box<[&'static str]>,
) -> Self {
assert_eq!(ckeys.len(), ckeys.len());
Self {
index,
name,
ckeys,
cnames,
}
}
pub(crate) const fn index(&self) -> EntityIndex {
self.index
}
pub const fn get_name(&self) -> Option<&EntityName> {
self.name.as_ref()
}
pub(crate) const fn get_component_keys(&self) -> &Arc<[ComponentKey]> {
&self.ckeys
}
pub const fn get_component_names(&self) -> &[&'static str] {
&self.cnames
}
}
impl PartialEq for EntityTag {
fn eq(&self, other: &Self) -> bool {
self.index() == other.index()
}
}