use core::fmt::*;
use std::sync::atomic::Ordering;
use std::{any::TypeId, cell::UnsafeCell};
use pi_append_vec::AppendVec;
use pi_arr::Iter;
use pi_null::Null;
use pi_share::ShareUsize;
use smallvec::SmallVec;
use crate::archetype::{Archetype, ColumnIndex, Row};
use crate::world::Entity;
#[derive(Debug, Default, Clone, Copy)]
pub struct DirtyIndex {
column_index: i32, vec_index: u32, }
impl DirtyIndex {
#[inline]
pub fn new(is_changed: bool, column_index: ColumnIndex, vec_index: usize) -> Self {
let column_index = if is_changed {
column_index as i32
} else {
-(column_index as i32 + 1)
};
DirtyIndex {
column_index,
vec_index: vec_index as u32,
}
}
#[inline]
pub(crate) fn get_iter<'a>(self, archetype: &'a Archetype) -> Iter<'a, EntityDirty> {
let r = if self.column_index >= 0 {
&archetype
.table
.get_column_unchecked(self.column_index as u32)
.changed
} else {
&archetype
.table
.get_column_unchecked(-self.column_index as u32 - 1)
.added
};
let end = r.vec.len();
let len = unsafe { &r.listener_list().get_unchecked(self.vec_index as usize).1 };
let start = len.load(Ordering::Relaxed);
len.store(end, Ordering::Relaxed);
r.vec.slice(start..end)
}
}
#[derive(Debug, Default)]
pub(crate) struct EntityDirty {
pub(crate) e: Entity,
pub(crate) row: Row,
}
impl Null for EntityDirty {
fn is_null(&self) -> bool {
self.e.is_null()
}
fn null() -> Self {
EntityDirty {
e: Entity::null(),
row: Row::null(),
}
}
}
#[derive(Debug, Default)]
pub struct ComponentDirty {
listeners: UnsafeCell<Vec<(TypeId, ShareUsize)>>, vec: AppendVec<EntityDirty>, }
unsafe impl Sync for ComponentDirty {}
unsafe impl Send for ComponentDirty {}
impl ComponentDirty {
pub(crate) fn insert_listener(&self, owner: TypeId) {
unsafe { &mut *self.listeners.get() }.push((owner, ShareUsize::new(0)));
}
pub(crate) fn listener_list(&self) -> &Vec<(TypeId, ShareUsize)> {
unsafe { &*self.listeners.get() }
}
pub fn find(
&self,
index: ColumnIndex,
owner: TypeId,
changed: bool,
result: &mut SmallVec<[DirtyIndex; 1]>,
) {
for (j, d) in self.listener_list().iter().enumerate() {
if d.0 == owner {
result.push(DirtyIndex::new(changed, index, j))
}
}
}
#[inline(always)]
pub(crate) fn listener_len(&self) -> usize {
self.listener_list().len()
}
#[inline(always)]
pub(crate) fn record_unchecked(&self, e: Entity, row: Row) {
self.vec.insert(EntityDirty { e, row });
}
#[inline(always)]
pub(crate) fn record(&self, e: Entity, row: Row) {
if !self.listener_list().is_empty() {
self.vec.insert(EntityDirty { e, row });
}
}
#[inline(always)]
pub fn reserve(&mut self, additional: usize) {
if self.listener_len() > 0 {
self.vec.reserve(additional);
}
}
pub(crate) fn collect(&mut self) -> bool {
let listeners = self.listeners.get_mut();
if listeners.is_empty() {
return true;
}
let len = self.vec.len();
if len == 0 {
return true;
}
for (_, read_len) in listeners.iter_mut() {
if *read_len.get_mut() < len {
return false;
}
}
self.vec.clear();
if self.vec.vec_capacity() < len {
unsafe { self.vec.vec_reserve(len - self.vec.vec_capacity()) };
}
for (_, read_len) in listeners.iter_mut() {
*read_len.get_mut() = 0;
}
true
}
}