use std::marker::PhantomData;
use std::mem::{transmute, MaybeUninit};
use std::ops::{Deref, DerefMut, Range};
use pi_null::Null;
use pi_share::Share;
use crate::archetype::*;
use crate::column::{BlobRef, Column};
use crate::fetch::FetchComponents;
use crate::filter::FilterComponents;
use crate::insert::Bundle;
use crate::query::{LocalIndex, Query, QueryError, QueryIter, QueryState};
use crate::system::SystemMeta;
use crate::system_params::SystemParam;
use crate::utils::VecExt;
use crate::world::*;
pub struct Alter<
'w,
Q: FetchComponents + 'static,
F: FilterComponents + 'static = (),
A: Bundle = (),
D: Bundle = (),
> {
query: Query<'w, Q, F>,
state: &'w mut AlterState<A>,
_k: PhantomData<D>,
}
unsafe impl<'w, Q: FetchComponents + 'static, F: FilterComponents + 'static, A: Bundle, D: Bundle>
Send for Alter<'w, Q, F, A, D>
{
}
unsafe impl<'w, Q: FetchComponents + 'static, F: FilterComponents + 'static, A: Bundle, D: Bundle>
Sync for Alter<'w, Q, F, A, D>
{
}
impl<'w, Q: FetchComponents + 'static, F: FilterComponents + 'static, A: Bundle, D: Bundle>
Alter<'w, Q, F, A, D>
{
pub(crate) fn new(query: Query<'w, Q, F>, state: &'w mut AlterState<A>) -> Self {
Alter {
query,
state,
_k: PhantomData,
}
}
pub fn contains(&self, entity: Entity) -> bool {
self.query.contains(entity)
}
pub fn get(
&self,
e: Entity,
) -> Result<<<Q as FetchComponents>::ReadOnly as FetchComponents>::Item<'_>, QueryError> {
self.query.get(e)
}
pub fn get_mut(&mut self, e: Entity) -> Result<<Q as FetchComponents>::Item<'_>, QueryError> {
self.query.get_mut(e)
}
pub fn is_empty(&self) -> bool {
self.query.is_empty()
}
pub fn len(&self) -> usize {
self.query.len()
}
pub fn iter(&self) -> QueryIter<'_, <Q as FetchComponents>::ReadOnly, F> {
self.query.iter()
}
pub fn iter_mut(&mut self) -> AlterIter<'_, Q, F, A> {
AlterIter {
it: self.query.iter_mut(),
state: &mut self.state,
}
}
pub fn destroy(&mut self, e: Entity) -> Result<bool, QueryError> {
self.state.destroy(&self.query.world, e)
}
pub fn alter(&mut self, e: Entity, components: A) -> Result<bool, QueryError> {
let (addr, local_index) = self.state.check(&self.query.world, e)?;
self.state.alter(
&self.query.world,
local_index,
e,
addr,
components,
self.query.tick,
)
}
}
impl<
Q: FetchComponents + 'static,
F: FilterComponents + Send + Sync + 'static,
A: Bundle + 'static,
D: Bundle + Send + 'static,
> SystemParam for Alter<'_, Q, F, A, D>
{
type State = QueryAlterState<Q, F, A, D>;
type Item<'w> = Alter<'w, Q, F, A, D>;
fn init_state(world: &mut World, system_meta: &mut SystemMeta) -> Self::State {
let q = Query::init_state(world, system_meta);
QueryAlterState(
q,
AlterState::make(world, A::components(Vec::with_capacity(256)), D::components(Vec::with_capacity(256))),
PhantomData,
)
}
fn align(world: &World, _system_meta: &SystemMeta, state: &mut Self::State) {
state.0.align(world);
}
fn get_param<'w>(
world: &'w World,
_system_meta: &'w SystemMeta,
state: &'w mut Self::State,
tick: Tick,
) -> Self::Item<'w> {
state.1.align(world, &state.0.archetypes);
Alter::new(Query::new(world, &mut state.0, tick), &mut state.1)
}
fn get_self<'w>(
world: &'w World,
system_meta: &'w SystemMeta,
state: &'w mut Self::State,
tick: Tick,
) -> Self {
unsafe { transmute(Self::get_param(world, system_meta, state, tick)) }
}
}
impl<'w, Q: FetchComponents + 'static, F: FilterComponents + 'static, A: Bundle, D: Bundle> Drop
for Alter<'w, Q, F, A, D>
{
fn drop(&mut self) {
self.state.state.clear(
self.query.world,
&mut self.state.vec,
&mut self.state.mapping_dirtys,
);
}
}
pub struct QueryAlterState<
Q: FetchComponents + 'static,
F: FilterComponents + 'static,
A: Bundle,
D: Bundle,
>(
pub(crate) QueryState<Q, F>,
pub(crate) AlterState<A>,
pub(crate) PhantomData<D>,
);
unsafe impl<Q: FetchComponents + 'static, F: FilterComponents + 'static, A: Bundle, D: Bundle> Send
for QueryAlterState<Q, F, A, D>
{
}
unsafe impl<Q: FetchComponents + 'static, F: FilterComponents + 'static, A: Bundle, D: Bundle> Sync
for QueryAlterState<Q, F, A, D>
{
}
impl<Q: FetchComponents + 'static, F: FilterComponents + 'static, A: Bundle, D: Bundle>
QueryAlterState<Q, F, A, D>
{
pub fn get_param<'w>(&'w mut self, world: &'w World) -> Alter<'_, Q, F, A, D> {
Alter::new(Query::new(world, &mut self.0, world.tick()), &mut self.1)
}
}
pub struct AlterState<A: Bundle> {
bundle_vec: Vec<MaybeUninit<A::Item>>, pub(crate) vec: Vec<ArchetypeMapping>, mapping_dirtys: Vec<LocalIndex>, state: AState,
}
impl<A: Bundle> Deref for AlterState<A> {
type Target = AState;
fn deref(&self) -> &Self::Target {
&self.state
}
}
impl<A: Bundle> DerefMut for AlterState<A> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.state
}
}
impl<A: Bundle> AlterState<A> {
pub(crate) fn make(
world: &mut World,
add: Vec<ComponentInfo>,
remove: Vec<ComponentInfo>,
) -> Self {
let state = AState::make(world, add, remove);
Self {
bundle_vec: Vec::with_capacity(256),
vec: Vec::with_capacity(256),
mapping_dirtys: Vec::with_capacity(256),
state,
}
}
pub(crate) fn align(&mut self, world: &World, archetypes: &Vec<ShareArchetype>) {
for i in self.vec.len()..archetypes.len() {
let ar = unsafe { archetypes.get_unchecked(i).clone() };
self.push_archetype(world, ar);
}
}
pub(crate) fn push_archetype(&mut self, world: &World, ar: ShareArchetype) {
self.state.push_map(ar.index(), self.vec.len());
self.vec
.push(ArchetypeMapping::new(ar, world.empty_archetype().clone()));
self.bundle_vec.push(MaybeUninit::uninit());
}
pub(crate) fn alter<'w>(
&mut self,
world: &'w World,
ar_index: LocalIndex,
e: Entity,
addr: &mut EntityAddr,
components: A,
tick: Tick,
) -> Result<bool, QueryError> {
let mapping = unsafe { self.vec.get_unchecked_mut(ar_index.index()) };
let (is_new, _new_ar) = self.state.find_mapping(world, mapping, false);
if is_new {
let s = unsafe { self.bundle_vec.get_unchecked_mut(ar_index.index()) };
*s = MaybeUninit::new(A::init_item(world, &mapping.dst));
}
if mapping.dst.id() == mapping.src.id() {
let item = unsafe {
self.bundle_vec
.get_unchecked(ar_index.index())
.assume_init_ref()
};
A::insert(item, components, e, addr.row, tick);
return Ok(false);
}
if addr.is_mark() {
return Err(QueryError::RepeatAlter);
} else {
addr.mark();
}
let (_, dst_row) = mapping.dst.alloc();
let item = unsafe {
self.bundle_vec
.get_unchecked(ar_index.index())
.assume_init_ref()
};
A::insert(item, components, e, dst_row.into(), tick);
mapping.push(
addr.row,
dst_row.into(),
e,
ar_index,
&mut self.mapping_dirtys,
);
Ok(true)
}
}
#[derive(Debug)]
pub struct AState {
map: Vec<LocalIndex>, map_start: usize,
sorted_add_removes: Vec<(ComponentIndex, bool)>,
pub(crate) adding: Vec<Share<Column>>, moving: Vec<Share<Column>>, removing: Vec<Share<Column>>, }
impl AState {
pub(crate) fn make(
world: &mut World,
add: Vec<ComponentInfo>,
remove: Vec<ComponentInfo>,
) -> Self {
let mut sorted_add_removes = Vec::with_capacity(256);
world.add_component_indexs(add, &mut sorted_add_removes, true);
world.add_component_indexs(remove, &mut sorted_add_removes, false);
sorted_add_removes.sort_unstable();
Self::new(sorted_add_removes)
}
pub(crate) fn new(sorted_add_removes: Vec<(ComponentIndex, bool)>) -> Self {
Self {
map: Default::default(),
map_start: 0,
sorted_add_removes,
adding: Default::default(),
moving: Default::default(),
removing: Default::default(),
}
}
pub(crate) fn push_map(&mut self, index: ArchetypeIndex, len: usize) {
if len == 0 {
self.map_start = index.index();
}
let index = index.index() - self.map_start;
self.map.insert_value(index, len.into());
}
pub(crate) fn clear<'a>(
&self,
world: &'a World,
vec: &mut Vec<ArchetypeMapping>, mapping_dirtys: &mut Vec<LocalIndex>,
) {
for ar_index in mapping_dirtys.drain(..) {
let am = unsafe { vec.get_unchecked_mut(ar_index.index()) };
for i in (0..am.moves.len()).rev() {
let (src_row, dst_row, e) = unsafe { am.moves.get_unchecked(i) };
if src_row.is_null() {
continue;
}
let old = am.src.mark_remove(*src_row);
if old.is_null() {
self.destroy_add_columns(am, *dst_row, *e);
am.moves.swap_remove(i);
}
}
self.move_columns(am);
self.remove_columns(am);
for (_, dst_row, e) in am.moves.iter() {
am.dst.set(*dst_row, *e);
world.replace(*e, am.dst_index, *dst_row);
}
am.moves.clear();
}
}
pub(crate) fn destroy_add_columns(&self, am: &ArchetypeMapping, dst_row: Row, e: Entity) {
for index in am.add_indexs.clone() {
let c = unsafe { self.adding.get_unchecked(index) };
if c.info().drop_fn.is_some() {
let column = c.blob_ref_unchecked(am.dst_index);
column.drop_row_unchecked(dst_row, e);
}
}
am.dst.removes.insert(dst_row);
}
pub(crate) fn move_columns(&self, am: &mut ArchetypeMapping) {
for index in am.move_indexs.clone() {
let c = unsafe { self.moving.get_unchecked(index) };
let src_column = c.blob_ref_unchecked(am.src.index());
let dst_column = c.blob_ref_unchecked(am.dst.index());
Self::move_column(src_column, dst_column, &am.moves, c.info().is_tick());
}
}
pub(crate) fn move_column<'a>(
src_column: BlobRef<'a>,
dst_column: BlobRef<'a>,
moves: &Vec<(Row, Row, Entity)>,
is_tick: bool,
) {
for (src_row, dst_row, e) in moves.iter() {
let src_data: *mut u8 = src_column.get_row(*src_row, *e);
dst_column.write_row(*dst_row, *e, src_data);
}
if is_tick {
for (src_row, dst_row, _e) in moves.iter() {
let tick = src_column.get_tick_unchecked(*src_row);
dst_column.set_tick_unchecked(*dst_row, tick);
}
}
}
pub(crate) fn remove_columns(&self, am: &mut ArchetypeMapping) {
for i in am.removed_indexs.clone().into_iter() {
let c = unsafe { self.removing.get_unchecked(i) };
if c.info().drop_fn.is_some() {
let column = c.blob_ref_unchecked(am.src.index());
for (src_row, _dst_row, e) in am.moves.iter() {
column.drop_row_unchecked(*src_row, *e)
}
}
if let Some(record) = &c.info.removed {
for (_src_row, _dst_row, e) in am.moves.iter() {
record.record(*e);
}
}
}
}
pub(crate) fn find_mapping<'a>(
&mut self,
world: &'a World,
mapping: &mut ArchetypeMapping,
existed_adding_is_move: bool,
) -> (bool, bool) {
if !mapping.dst_index.is_null() {
return (false, false);
}
let add_start: usize = self.adding.len();
let move_start = self.moving.len();
let removing_start = self.removing.len();
let info = mapping.src.alter(
world,
&mut self.sorted_add_removes,
&mut self.adding,
&mut self.moving,
&mut self.removing,
existed_adding_is_move,
);
mapping.add_indexs = add_start..self.adding.len();
mapping.move_indexs = move_start..self.moving.len();
mapping.removed_indexs = removing_start..self.removing.len();
if info.id == mapping.src.id() {
mapping.dst = mapping.src.clone();
mapping.dst_index = mapping.src.index();
return (true, false);
}
let dst = world.find_archtype(info);
mapping.dst_index = dst.index();
mapping.dst = dst;
(true, true)
}
pub(crate) fn alter_row(
&self,
world: &World,
mapping: &ArchetypeMapping, src_row: Row,
dst_row: Row,
e: Entity,
) {
if !src_row.is_null() {
mapping.src.mark_remove(src_row);
mapping.move_columns(src_row, dst_row, e, &self.moving);
mapping.remove_columns(src_row, e, &self.removing);
}
mapping.dst.set(dst_row, e);
world.replace(e, mapping.dst_index, dst_row);
}
fn destroy(&self, world: &World, e: Entity) -> Result<bool, QueryError> {
let (addr, _local_index) = self.check(world, e)?;
if addr.row.is_null() {
world.entities.remove(e).unwrap();
return Ok(true);
}
let ar = unsafe { world.get_archetype_unchecked(addr.archetype_index()) };
Self::destroy_row(world, ar, addr.row)
}
pub(crate) fn destroy_row(world: &World, ar: &Archetype, row: Row) -> Result<bool, QueryError> {
let e = ar.destroy(row);
if e.is_null() {
return Err(QueryError::NoSuchRow(row));
}
world.entities.remove(e).unwrap();
Ok(true)
}
pub(crate) fn check<'w>(
&self,
world: &'w World,
entity: Entity,
) -> Result<(&'w mut EntityAddr, LocalIndex), QueryError> {
let addr = match world.entities.load(entity) {
Some(v) => v,
None => return Err(QueryError::NoSuchEntity(entity)),
};
let index = addr.archetype_index().index().wrapping_sub(self.map_start);
match self.map.get(index) {
Some(v) if !v.is_null() => Ok((addr, *v)),
_ => Err(QueryError::NoMatchArchetype),
}
}
}
#[derive(Debug)]
pub struct ArchetypeMapping {
pub(crate) src: ShareArchetype, pub(crate) dst: ShareArchetype, pub(crate) dst_index: ArchetypeIndex, pub(crate) add_indexs: Range<usize>, pub(crate) move_indexs: Range<usize>, pub(crate) removed_indexs: Range<usize>, pub(crate) moves: Vec<(Row, Row, Entity)>, }
impl ArchetypeMapping {
pub fn new(src: ShareArchetype, dst: ShareArchetype) -> Self {
ArchetypeMapping {
src,
dst,
dst_index: ArchetypeIndex::null(),
move_indexs: 0..0,
add_indexs: 0..0,
removed_indexs: 0..0,
moves: Default::default(),
}
}
pub(crate) fn push(
&mut self,
src_row: Row,
dst_row: Row,
e: Entity,
ar_index: LocalIndex,
mapping_dirtys: &mut Vec<LocalIndex>,
) {
self.moves.push((src_row, dst_row, e));
if self.moves.len() == 1 {
mapping_dirtys.push(ar_index);
}
}
pub(crate) fn move_columns(
&self,
src_row: Row,
dst_row: Row,
e: Entity,
moving: &Vec<Share<Column>>,
) {
for index in self.move_indexs.clone() {
let c = unsafe { moving.get_unchecked(index) };
let src_column = c.blob_ref_unchecked(self.src.index());
let dst_column = c.blob_ref_unchecked(self.dst.index());
self.move_column(
src_row,
dst_row,
e,
src_column,
dst_column,
c.info().is_tick(),
);
}
}
pub(crate) fn move_column<'a>(
&self,
src_row: Row,
dst_row: Row,
e: Entity,
src_column: BlobRef<'a>,
dst_column: BlobRef<'a>,
is_tick: bool,
) {
let src_data: *mut u8 = src_column.get_row(src_row, e);
dst_column.write_row(dst_row, e, src_data);
if is_tick {
let tick = src_column.get_tick_unchecked(src_row);
dst_column.set_tick_unchecked(dst_row, tick);
}
}
pub(crate) fn remove_columns(&self, src_row: Row, e: Entity, removing: &Vec<Share<Column>>) {
for i in self.removed_indexs.clone().into_iter() {
let c = unsafe { removing.get_unchecked(i) };
if c.info().drop_fn.is_some() {
let src_column = c.blob_ref_unchecked(self.src.index());
src_column.drop_row_unchecked(src_row, e);
}
if let Some(record) = &c.info.removed {
record.record(e);
}
}
}
}
pub struct AlterIter<'w, Q: FetchComponents + 'static, F: FilterComponents + 'static, A: Bundle> {
it: QueryIter<'w, Q, F>,
state: &'w mut AlterState<A>,
}
impl<'w, Q: FetchComponents, F: FilterComponents, A: Bundle> AlterIter<'w, Q, F, A> {
pub fn entity(&self) -> Entity {
self.it.entity()
}
pub fn destroy(&mut self) -> Result<bool, QueryError> {
AState::destroy_row(&self.it.world, &self.it.ar, self.it.row)
}
pub fn alter(&mut self, components: A) -> Result<bool, QueryError> {
let addr = self.it.world.entities.load(self.it.e).unwrap();
self.state.alter(
&self.it.world,
self.it.ar_index,
self.it.e,
addr,
components,
self.it.tick,
)
}
}
impl<'w, Q: FetchComponents, F: FilterComponents, A: Bundle> Iterator for AlterIter<'w, Q, F, A> {
type Item = Q::Item<'w>;
fn next(&mut self) -> Option<Self::Item> {
self.it.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.it.size_hint()
}
}