use core::fmt::*;
use std::any::TypeId;
use std::borrow::Cow;
use std::mem::{needs_drop, size_of, transmute};
use std::sync::atomic::Ordering;
use bitflags::bitflags;
use fixedbitset::FixedBitSet;
use pi_null::Null;
use pi_phf_map::PhfMap;
use pi_share::{Share, ShareU32};
use smallvec::SmallVec;
use crate::column::Column;
use crate::dirty::DirtyIndex;
use crate::table::Table;
use crate::world::World;
pub type ShareArchetype = Share<Archetype>;
pub type Row = u32;
pub type ArchetypeWorldIndex = u32;
pub type ColumnIndex = u32;
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Flags: u32 {
const WITHOUT = 0b00001;
const READ = 0b00010;
const WRITE = 0b00100;
const DELETE = 0b01000;
const SHARE_WRITE = 0b10000;
}
}
#[derive(Debug, PartialEq)]
pub enum ArchetypeDepend {
Flag(Flags),
Alter((u128, Cow<'static, str>)),
}
#[derive(Debug, PartialEq)]
pub struct ArchetypeDependResult {
pub flag: Flags,
pub alters: SmallVec<[(u128, Cow<'static, str>); 1]>,
}
impl ArchetypeDependResult {
pub fn new() -> Self {
Self {
flag: Flags::empty(),
alters: SmallVec::new(),
}
}
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 clear(&mut self) {
self.flag = Flags::empty();
self.alters.clear();
}
}
pub struct Archetype {
id: u128,
name: Cow<'static, str>,
pub(crate) table: Table,
map: PhfMap<TypeId, ColumnIndex>,
pub(crate) index: ShareU32, }
impl Archetype {
pub fn new(mut components: Vec<ComponentInfo>) -> Self {
let mut id = 0;
let mut s = String::new();
let mut vec1 = Vec::with_capacity(components.capacity());
for (i, info) in components.iter_mut().enumerate() {
id ^= info.id();
s.push_str(&info.type_name);
s.push('+');
vec1.push((info.type_id, i as u32));
}
if s.len() > 0 {
s.pop();
}
Self {
id,
name: s.into(),
table: Table::new(components),
map: PhfMap::new(vec1),
index: ShareU32::new(u32::null()),
}
}
#[inline(always)]
pub fn index(&self) -> ArchetypeWorldIndex {
self.index.load(Ordering::Relaxed)
}
pub fn alter(
&self,
sort_add: &Vec<ComponentInfo>,
sort_del: &Vec<TypeId>,
) -> (Vec<ComponentInfo>, Vec<TypeId>) {
let mut add = sort_add.clone();
let mut moving = Vec::new();
for c in self.table.columns.iter() {
if sort_del.binary_search(&c.info().type_id).is_err()
&& sort_add.binary_search(&c.info()).is_err()
{
add.push(c.info().clone());
moving.push(c.info().type_id);
}
}
(add, moving)
}
pub(crate) unsafe fn add_dirty_listeners(
&self,
owner: TypeId,
listeners: &SmallVec<[(TypeId, bool); 1]>,
) {
for (tid, changed) in listeners.iter() {
let index = self.get_column_index(tid);
if index.is_null() {
continue;
}
let c = self.table.get_column_unchecked(index);
if *changed {
c.changed.insert_listener(owner);
} else {
c.added.insert_listener(owner);
}
}
}
pub fn find_dirty_listeners(
&self,
owner: TypeId,
listens: &SmallVec<[(TypeId, bool); 1]>,
vec: &mut SmallVec<[DirtyIndex; 1]>,
) {
for (tid, changed) in listens.iter() {
let index = self.get_column_index(tid);
if index.is_null() {
continue;
}
let c = self.table.get_column_unchecked(index);
let d = if *changed { &c.changed } else { &c.added };
d.find(index, owner, *changed, vec);
}
}
#[inline(always)]
pub fn id(&self) -> &u128 {
&self.id
}
#[inline]
pub fn name(&self) -> &Cow<'static, str> {
&self.name
}
#[inline(always)]
pub fn get_columns(&self) -> &Vec<Column> {
&self.table.columns
}
#[inline(always)]
pub fn get_column_index(&self, type_id: &TypeId) -> ColumnIndex {
if let Some(t) = self.map.get(&type_id) {
if t.is_null() {
return u32::null();
}
let ti = unsafe { self.table.columns.get_unchecked(*t as usize) };
if &ti.info().type_id == type_id {
return *t;
}
}
u32::null()
}
#[inline(always)]
pub fn get_column(&self, type_id: &TypeId) -> Option<&Column> {
if let Some(t) = self.map.get(&type_id) {
if t.is_null() {
return None;
}
let t = unsafe { self.table.columns.get_unchecked(*t as usize) };
if &t.info().type_id == type_id {
return Some(t);
}
}
None
}
#[inline(always)]
pub unsafe fn get_column_unchecked(&self, type_id: &TypeId) -> &Column {
self.table
.columns
.get_unchecked(*self.map.get_unchecked(&type_id) as usize)
}
#[inline(always)]
pub fn len(&self) -> usize {
self.table.len() as usize
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.table.columns.len() == 0
}
pub(crate) fn collect(
&mut self,
world: &World,
action: &mut Vec<(Row, Row)>,
set: &mut FixedBitSet,
) {
let _r = self.table.collect(world, action, set);
}
}
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, Clone, PartialEq, Eq, Hash)]
pub struct ComponentInfo {
pub type_id: TypeId,
pub type_name: Cow<'static, str>,
pub drop_fn: Option<fn(*mut u8)>,
pub mem_size: usize, }
impl ComponentInfo {
pub fn of<T: 'static>() -> ComponentInfo {
ComponentInfo::create(
TypeId::of::<T>(),
std::any::type_name::<T>().into(),
get_drop::<T>(),
size_of::<T>(),
)
}
pub fn create(
type_id: TypeId,
type_name: Cow<'static, str>,
drop_fn: Option<fn(*mut u8)>,
mem_size: usize,
) -> Self {
ComponentInfo {
type_id,
type_name,
drop_fn,
mem_size,
}
}
pub fn id(&self) -> u128 {
unsafe { transmute::<TypeId, u128>(self.type_id) }.into()
}
pub fn calc_id(vec: &Vec<ComponentInfo>) -> u128 {
let mut id = 0;
for c in vec.iter() {
id ^= c.id();
}
id
}
pub fn calc_id_name(vec: &Vec<ComponentInfo>) -> (u128, Cow<'static, str>) {
let mut id = 0;
let mut s = String::new();
for c in vec.iter() {
id ^= c.id();
s.push_str(&c.type_name);
s.push('+');
}
if s.len() > 0 {
s.pop();
}
(id, s.into())
}
}
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() })
}