use core::fmt::*;
use std::any::TypeId;
use std::borrow::Cow;
use std::hash::{DefaultHasher, Hash, Hasher};
use std::mem::{needs_drop, size_of, transmute};
use std::ops::{Deref, DerefMut};
use std::sync::atomic::Ordering;
use bitflags::bitflags;
use pi_null::Null;
use pi_share::{Share, ShareBool};
use crate::column::Column;
use crate::system::TypeInfo;
use crate::table::Table;
use crate::world::{ComponentIndex, SetFromWorld, World};
pub type ShareArchetype = Share<Archetype>;
#[derive(Debug, Clone, Copy, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Row(pub(crate) u32);
impl Row {
#[inline(always)]
pub fn index(&self) -> usize {
self.0 as usize
}
}
impl From<u32> for Row {
#[inline(always)]
fn from(index: u32) -> Self {
Self(index)
}
}
impl From<usize> for Row {
#[inline(always)]
fn from(index: usize) -> Self {
Self(index as u32)
}
}
impl pi_null::Null for Row {
#[inline(always)]
fn null() -> Self {
Self(u32::null())
}
#[inline(always)]
fn is_null(&self) -> bool {
self.0 == u32::null()
}
}
#[derive(Debug, Clone, Copy, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct ArchetypeIndex(pub(crate) i32);
impl ArchetypeIndex {
#[inline(always)]
pub fn index(&self) -> usize {
self.0 as usize
}
}
impl From<u32> for ArchetypeIndex {
#[inline(always)]
fn from(index: u32) -> Self {
Self(index as i32)
}
}
impl From<usize> for ArchetypeIndex {
#[inline(always)]
fn from(index: usize) -> Self {
Self(index as i32)
}
}
impl pi_null::Null for ArchetypeIndex {
#[inline(always)]
fn null() -> Self {
Self(i32::null())
}
#[inline(always)]
fn is_null(&self) -> bool {
self.0.is_null()
}
}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Flags: u32 {
const WITHOUT = 0b000000001; const OPTION = 0b000000010; const READ = 0b000000100; const WRITE = 0b000001000; const MOVE = 0b000010000; const ENTITY_EDIT = 0b000100000; const SHARE_WRITE = 0b001000000; const WORLD_READ = 0b010000000; const WORLD_WRITE = 0b100000000; }
}
#[derive(Debug, PartialEq)]
pub enum ArchetypeDepend {
Flag(Flags),
Alter((u128, Cow<'static, str>, Vec<Share<ComponentInfo>>)),
}
#[derive(Debug, PartialEq)]
pub struct ArchetypeDependResult {
pub flag: Flags,
pub reads: Vec<ComponentIndex>,
pub writes: Vec<ComponentIndex>,
pub alters: Vec<(u128, Cow<'static, str>, Vec<Share<ComponentInfo>>)>,
}
impl ArchetypeDependResult {
pub fn new() -> Self {
Self {
flag: Flags::empty(),
reads: Vec::with_capacity(256),
writes: Vec::with_capacity(256),
alters: Vec::with_capacity(256),
}
}
pub fn merge(&mut self, depend: ArchetypeDepend) {
match depend {
ArchetypeDepend::Flag(f) => self.flag |= f,
ArchetypeDepend::Alter(t) if !self.flag.contains(Flags::WITHOUT) => self.alters.push(t),
_ => (),
}
}
pub fn insert(&mut self, ar: &Archetype, world: &World, components: Vec<ComponentInfo>) {
let id = ComponentInfo::calc_id(&components);
self.merge(ArchetypeDepend::Flag(Flags::WRITE));
for c in components {
let index = world.get_component_index(&c.type_id());
self.writes.push(index);
}
}
pub fn depend(
&mut self,
_ar: &Archetype,
_world: &World,
_tid: &TypeId,
_false_result: Flags,
_true_result: Flags,
) {
todo!()
}
pub fn clear(&mut self) {
self.flag = Flags::empty();
self.reads.clear();
self.writes.clear();
self.alters.clear();
}
}
pub struct Archetype {
id: u64,
name: Cow<'static, str>,
table: Table,
pub(crate) ready: ShareBool, }
impl Archetype {
pub(crate) fn new(info: ArchetypeInfo) -> Self {
let name = info.name();
Self {
id: info.id,
name,
table: Table::new(info.sorted_components),
ready: ShareBool::new(false),
}
}
#[inline(always)]
pub(crate) fn set_index(&mut self, index: ArchetypeIndex) {
self.table.index = index;
}
#[inline(always)]
pub fn index(&self) -> ArchetypeIndex {
self.table.index
}
#[inline(always)]
pub fn ready(&self) -> bool {
self.ready.load(Ordering::Relaxed)
}
pub(crate) fn alter(
&self,
world: &World,
sorted_add_removes: &[(ComponentIndex, bool)], adding: &mut Vec<Share<Column>>,
moving: &mut Vec<Share<Column>>,
removing: &mut Vec<Share<Column>>,
existed_adding_is_move: bool,
) -> ArchetypeInfo {
let mut result = Vec::with_capacity(256);
let mut column_index = 0;
let len = self.column_len();
let mut pre_index = ComponentIndex::null();
for (index, add) in sorted_add_removes.iter() {
if pre_index == *index {
continue;
} else {
pre_index = *index;
}
loop {
if column_index >= len {
if *add {
let c = world.get_column(*index).unwrap();
adding.push(c.clone());
result.push(c.clone());
}
break; }
let c = self.get_column_unchecked(column_index);
let info = c.info();
if info.index > *index {
if *add {
let c = world.get_column(*index).unwrap();
adding.push(c.clone());
result.push(c.clone());
}
break; }
if info.index < *index {
moving.push(c.clone());
result.push(c.clone());
column_index += 1;
continue; }
if *add {
if existed_adding_is_move {
moving.push(c.clone());
}else{
adding.push(c.clone());
}
result.push(c.clone());
} else {
removing.push(c.clone());
}
column_index += 1;
break; }
}
while column_index < len {
let c = self.get_column_unchecked(column_index.into());
moving.push(c.clone());
result.push(c.clone());
column_index += 1;
}
ArchetypeInfo::new(result)
}
#[inline(always)]
pub fn id(&self) -> u64 {
self.id
}
#[inline]
pub fn name(&self) -> &Cow<'static, str> {
&self.name
}
#[inline(always)]
pub fn column_len(&self) -> usize {
self.get_columns().len()
}
#[inline(always)]
pub fn is_empty_columns(&self) -> bool {
self.get_columns().len() == 0
}
}
impl Deref for Archetype {
type Target = Table;
fn deref(&self) -> &Self::Target {
&self.table
}
}
impl DerefMut for Archetype {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.table
}
}
impl Debug for Archetype {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
f.debug_struct("Archetype")
.field("id", &self.id)
.field("name", &self.name)
.field("table", &self.table)
.field("index", &self.index)
.finish()
}
}
#[derive(Debug, Default)]
pub struct ArchetypeInfo {
pub(crate) id: u64,
pub(crate) sorted_components: Vec<Share<Column>>,
}
impl ArchetypeInfo {
pub(crate) fn sort(mut components: Vec<Share<Column>>) -> Self {
components.sort_unstable_by(|a, b| a.info.index.cmp(&b.info.index));
Self::new(components)
}
pub(crate) fn new(sorted_components: Vec<Share<Column>>) -> Self {
let mut hasher = DefaultHasher::new();
for c in sorted_components.iter() {
c.info().index.hash(&mut hasher);
}
let id = hasher.finish();
Self {
id,
sorted_components,
}
}
pub(crate) fn name(&self) -> Cow<'static, str> {
let mut s = String::new();
for c in self.sorted_components.iter() {
s.push_str(&c.info().type_name());
s.push('+');
}
if s.len() > 0 {
s.pop();
}
s.into()
}
}
pub const COMPONENT_TICK: u8 = 1;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ComponentInfo {
pub type_info: Share<TypeInfo>,
pub drop_fn: Option<fn(*mut u8)>,
pub set_fn: Option<fn(&mut World, *mut u8)>,
pub index: ComponentIndex, pub mem_size: u32, pub tick_info: u8, }
impl ComponentInfo {
pub fn of<T: 'static>(tick_info: u8) -> ComponentInfo {
ComponentInfo::create(
TypeId::of::<T>(),
std::any::type_name::<T>().into(),
get_drop::<T>(),
<T as SetFromWorld>::set_fn(),
size_of::<T>() as u32,
tick_info,
)
}
pub fn create(
type_id: TypeId,
type_name: Cow<'static, str>,
drop_fn: Option<fn(*mut u8)>,
set_fn: Option<fn(&mut World, *mut u8)>,
mem_size: u32,
tick_info: u8,
) -> Self {
let type_info = Share::new(TypeInfo{type_id, type_name});
ComponentInfo {
type_info,
drop_fn,
set_fn,
mem_size,
index: ComponentIndex::null(),
tick_info,
}
}
pub fn type_id(&self) -> &TypeId {
&self.type_info.type_id
}
pub fn type_name(&self) -> &Cow<'static, str> {
&self.type_info.type_name
}
#[inline(always)]
pub fn size(&self) -> usize {
self.mem_size as usize
}
pub fn id(&self) -> u128 {
unsafe { transmute::<TypeId, u128>(*self.type_id()) }.into()
}
pub fn is_tick(&self) -> bool {
self.tick_info > 0
}
pub fn calc_id(vec: &Vec<ComponentInfo>) -> u128 {
let mut id = 0;
for c in vec.iter() {
id ^= c.id();
}
id
}
}
impl PartialOrd for ComponentInfo {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.type_id().partial_cmp(&other.type_id())
}
}
impl Ord for ComponentInfo {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.type_id().cmp(&other.type_id())
}
}
pub fn get_drop<T>() -> Option<fn(*mut u8)> {
needs_drop::<T>().then_some(|ptr: *mut u8| {
unsafe { (ptr as *mut T).drop_in_place() }
})
}