ecs: rename Changed<T> to Mutated<T>

This commit is contained in:
Carter Anderson 2020-07-22 12:42:12 -07:00
parent 19d24e92aa
commit e673faab7c
7 changed files with 74 additions and 56 deletions

View File

@ -99,7 +99,6 @@ impl Archetype {
self.state.contains_key(&id)
}
// TODO: this should be unsafe i think
#[allow(missing_docs)]
#[inline]
pub fn get<T: Component>(&self) -> Option<NonNull<T>> {
@ -111,27 +110,25 @@ impl Archetype {
})
}
// TODO: this should be unsafe i think
#[allow(missing_docs)]
#[inline]
pub fn get_with_modified<T: Component>(&self) -> Option<(NonNull<T>, NonNull<bool>)> {
pub fn get_with_mutated<T: Component>(&self) -> Option<(NonNull<T>, NonNull<bool>)> {
let state = self.state.get(&TypeId::of::<T>())?;
Some(unsafe {
(
NonNull::new_unchecked(
(*self.data.get()).as_ptr().add(state.offset).cast::<T>() as *mut T
),
NonNull::new_unchecked(state.modified_entities.as_ptr() as *mut bool),
NonNull::new_unchecked(state.mutated_entities.as_ptr() as *mut bool),
)
})
}
// TODO: this should be unsafe i think
#[allow(missing_docs)]
#[inline]
pub fn get_modified<T: Component>(&self) -> Option<NonNull<bool>> {
pub fn get_mutated<T: Component>(&self) -> Option<NonNull<bool>> {
let state = self.state.get(&TypeId::of::<T>())?;
Some(unsafe { NonNull::new_unchecked(state.modified_entities.as_ptr() as *mut bool) })
Some(unsafe { NonNull::new_unchecked(state.mutated_entities.as_ptr() as *mut bool) })
}
#[allow(missing_docs)]
@ -264,7 +261,7 @@ impl Archetype {
self.entities = new_entities;
for type_state in self.state.values_mut() {
type_state.modified_entities.resize_with(count, || false);
type_state.mutated_entities.resize_with(count, || false);
type_state.added_entities.resize_with(count, || false);
}
@ -325,7 +322,7 @@ impl Archetype {
);
let type_state = self.state.get_mut(&ty.id).unwrap();
type_state.modified_entities[index as usize] = type_state.modified_entities[last as usize];
type_state.mutated_entities[index as usize] = type_state.mutated_entities[last as usize];
type_state.added_entities[index as usize] = type_state.added_entities[last as usize];
}
}
@ -352,8 +349,8 @@ impl Archetype {
.as_ptr();
let type_state = self.state.get(&ty.id).unwrap();
let is_added= type_state.added_entities[index as usize];
let is_modified = type_state.modified_entities[index as usize];
f(moved, ty.id(), ty.layout().size(), is_added, is_modified);
let is_mutated = type_state.mutated_entities[index as usize];
f(moved, ty.id(), ty.layout().size(), is_added, is_mutated);
if index != last {
ptr::copy_nonoverlapping(
self.get_dynamic(ty.id, ty.layout.size(), last)
@ -364,7 +361,7 @@ impl Archetype {
);
let type_state = self.state.get_mut(&ty.id).unwrap();
type_state.added_entities[index as usize] = type_state.added_entities[last as usize];
type_state.modified_entities[index as usize] = type_state.modified_entities[last as usize];
type_state.mutated_entities[index as usize] = type_state.mutated_entities[last as usize];
}
}
self.len -= 1;
@ -415,7 +412,7 @@ impl Drop for Archetype {
pub struct TypeState {
offset: usize,
borrow: AtomicBorrow,
pub modified_entities: Vec<bool>,
pub mutated_entities: Vec<bool>,
pub added_entities: Vec<bool>,
}
@ -424,14 +421,14 @@ impl TypeState {
Self {
offset: 0,
borrow: AtomicBorrow::new(),
modified_entities: Vec::new(),
mutated_entities: Vec::new(),
added_entities: Vec::new(),
}
}
fn clear_trackers(&mut self) {
for modified in self.modified_entities.iter_mut() {
*modified = false;
for mutated in self.mutated_entities.iter_mut() {
*mutated = false;
}
for added in self.added_entities.iter_mut() {

View File

@ -126,7 +126,7 @@ impl<'a, T: Component> RefMut<'a, T> {
);
archetype.borrow_mut::<T>();
let modified = archetype
.get_modified::<T>()
.get_mutated::<T>()
.unwrap()
.as_ptr()
.add(index as usize);

View File

@ -80,7 +80,7 @@ pub use borrow::{EntityRef, Ref, RefMut};
pub use bundle::{Bundle, DynamicBundle, MissingComponent};
pub use entities::{Entity, Location, NoSuchEntity};
pub use entity_builder::{BuiltEntity, EntityBuilder};
pub use query::{Access, BatchedIter, Query, QueryBorrow, QueryIter, With, Without, Mut, Changed};
pub use query::{Access, BatchedIter, Query, QueryBorrow, QueryIter, With, Without, Mut, Mutated};
pub use query_one::QueryOne;
pub use world::{ArchetypesGeneration, Component, ComponentError, Iter, SpawnBatchIter, World};

View File

@ -153,7 +153,7 @@ impl<T: Query> Query for Option<T> {
/// Unique borrow of an entity's component
pub struct Mut<'a, T: Component> {
value: &'a mut T,
modified: &'a mut bool,
mutated: &'a mut bool,
}
unsafe impl<T: Component> Send for Mut<'_, T> {}
@ -170,7 +170,7 @@ impl<'a, T: Component> Deref for Mut<'a, T> {
impl<'a, T: Component> DerefMut for Mut<'a, T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
*self.modified = true;
*self.mutated = true;
self.value
}
}
@ -197,11 +197,11 @@ impl<'a, T: Component> Fetch<'a> for FetchMut<T> {
}
unsafe fn get(archetype: &'a Archetype, offset: usize) -> Option<Self> {
archetype
.get_with_modified::<T>()
.map(|(components, modified)| {
.get_with_mutated::<T>()
.map(|(components, mutated)| {
Self(
NonNull::new_unchecked(components.as_ptr().add(offset)),
NonNull::new_unchecked(modified.as_ptr().add(offset)),
NonNull::new_unchecked(mutated.as_ptr().add(offset)),
)
})
}
@ -212,37 +212,37 @@ impl<'a, T: Component> Fetch<'a> for FetchMut<T> {
#[inline]
unsafe fn next(&mut self) -> Mut<'a, T> {
let component = self.0.as_ptr();
let modified = self.1.as_ptr();
let mutated = self.1.as_ptr();
self.0 = NonNull::new_unchecked(component.add(1));
self.1 = NonNull::new_unchecked(modified.add(1));
self.1 = NonNull::new_unchecked(mutated.add(1));
Mut {
value: &mut *component,
modified: &mut *modified,
mutated: &mut *mutated,
}
}
}
#[allow(missing_docs)]
pub struct Changed<'a, T> {
pub struct Mutated<'a, T> {
value: &'a T,
}
impl<'a, T: Component> Deref for Changed<'a, T> {
impl<'a, T: Component> Deref for Mutated<'a, T> {
type Target = T;
fn deref(&self) -> &T {
self.value
}
}
impl<'a, T: Component> Query for Changed<'a, T> {
type Fetch = FetchChanged<T>;
impl<'a, T: Component> Query for Mutated<'a, T> {
type Fetch = FetchMutated<T>;
}
#[doc(hidden)]
pub struct FetchChanged<T>(NonNull<T>, NonNull<bool>);
pub struct FetchMutated<T>(NonNull<T>, NonNull<bool>);
impl<'a, T: Component> Fetch<'a> for FetchChanged<T> {
type Item = Changed<'a, T>;
impl<'a, T: Component> Fetch<'a> for FetchMutated<T> {
type Item = Mutated<'a, T>;
fn access(archetype: &Archetype) -> Option<Access> {
if archetype.has::<T>() {
@ -256,16 +256,21 @@ impl<'a, T: Component> Fetch<'a> for FetchChanged<T> {
archetype.borrow::<T>();
}
unsafe fn get(archetype: &'a Archetype, offset: usize) -> Option<Self> {
let components = NonNull::new_unchecked(archetype.get::<T>()?.as_ptr().add(offset));
let modified = NonNull::new_unchecked(archetype.get_modified::<T>()?.as_ptr().add(offset));
Some(Self(components, modified))
archetype
.get_with_mutated::<T>()
.map(|(components, mutated)| {
Self(
NonNull::new_unchecked(components.as_ptr().add(offset)),
NonNull::new_unchecked(mutated.as_ptr().add(offset)),
)
})
}
fn release(archetype: &Archetype) {
archetype.release::<T>();
}
unsafe fn should_skip(&self) -> bool {
// skip if the current item wasn't changed
// skip if the current item wasn't mutated
!*self.1.as_ref()
}
@ -274,7 +279,7 @@ impl<'a, T: Component> Fetch<'a> for FetchChanged<T> {
self.1 = NonNull::new_unchecked(self.1.as_ptr().add(1));
let value = self.0.as_ptr();
self.0 = NonNull::new_unchecked(value.add(1));
Changed { value: &*value }
Mutated { value: &*value }
}
}
@ -313,8 +318,8 @@ impl<'a, T: Component> Fetch<'a> for FetchAdded<T> {
}
unsafe fn get(archetype: &'a Archetype, offset: usize) -> Option<Self> {
let components = NonNull::new_unchecked(archetype.get::<T>()?.as_ptr().add(offset));
let modified = NonNull::new_unchecked(archetype.get_added::<T>()?.as_ptr().add(offset));
Some(Self(components, modified))
let added = NonNull::new_unchecked(archetype.get_added::<T>()?.as_ptr().add(offset));
Some(Self(components, added))
}
fn release(archetype: &Archetype) {
archetype.release::<T>();
@ -820,7 +825,7 @@ smaller_tuples_too!(tuple_impl, O, N, M, L, K, J, I, H, G, F, E, D, C, B, A);
#[cfg(test)]
mod tests {
use crate::{Changed, Entity, Mut, World};
use crate::{Entity, Mut, Mutated, World};
use std::{vec, vec::Vec};
use super::*;
@ -869,7 +874,7 @@ mod tests {
}
#[test]
fn modified_trackers() {
fn mutated_trackers() {
let mut world = World::default();
let e1 = world.spawn((A(0), B(0)));
let e2 = world.spawn((A(0), B(0)));
@ -884,7 +889,7 @@ mod tests {
fn get_changed_a(world: &World) -> Vec<Entity> {
world
.query::<(Changed<A>, Entity)>()
.query::<(Mutated<A>, Entity)>()
.iter()
.map(|(_a, e)| e)
.collect::<Vec<Entity>>()
@ -892,12 +897,12 @@ mod tests {
assert_eq!(get_changed_a(&world), vec![e1, e3]);
// ensure changing an entity's archetypes also moves its modified state
// ensure changing an entity's archetypes also moves its mutated state
world.insert(e1, (C,)).unwrap();
assert_eq!(get_changed_a(&world), vec![e3, e1], "changed entities list should not change (although the order will due to archetype moves)");
// spawning a new A entity should not change existing modified state
// spawning a new A entity should not change existing mutated state
world.insert(e1, (A(0), B)).unwrap();
assert_eq!(
get_changed_a(&world),
@ -905,7 +910,7 @@ mod tests {
"changed entities list should not change"
);
// removing an unchanged entity should not change modified state
// removing an unchanged entity should not change mutated state
world.despawn(e2).unwrap();
assert_eq!(
get_changed_a(&world),
@ -924,7 +929,7 @@ mod tests {
world.clear_trackers();
assert!(world
.query::<(Changed<A>, Entity)>()
.query::<(Mutated<A>, Entity)>()
.iter()
.map(|(_a, e)| e)
.collect::<Vec<Entity>>()
@ -947,10 +952,26 @@ mod tests {
}
let a_b_changed = world
.query::<(Changed<A>, Changed<B>, Entity)>()
.query::<(Mutated<A>, Mutated<B>, Entity)>()
.iter()
.map(|(_a, _b, e)| e)
.collect::<Vec<Entity>>();
assert_eq!(a_b_changed, vec![e2]);
}
#[test]
fn changed_or_added_query() {
let mut world = World::default();
let e1 = world.spawn((A(0), B(0)));
fn get_changed_or_added(world: &World) -> Vec<Entity> {
world
.query::<(Mutated<A>, Added<A>, Entity)>()
.iter()
.map(|(_a, _b, e)| e)
.collect::<Vec<Entity>>()
};
assert_eq!(get_changed_or_added(&world), vec![e1]);
world.clear_trackers();
}
}

View File

@ -386,11 +386,11 @@ impl World {
let target_index = target_arch.allocate(entity.id());
loc.archetype = target;
let old_index = mem::replace(&mut loc.index, target_index);
if let Some(moved) = source_arch.move_to(old_index, |ptr, ty, size, is_added, is_modified| {
if let Some(moved) = source_arch.move_to(old_index, |ptr, ty, size, is_added, is_mutated| {
target_arch.put_dynamic(ptr, ty, size, target_index, false);
let type_state = target_arch.get_type_state_mut(ty).unwrap();
type_state.added_entities[target_index as usize] = is_added;
type_state.modified_entities[target_index as usize] = is_modified;
type_state.mutated_entities[target_index as usize] = is_mutated;
}) {
self.entities.get_mut(Entity::with_id(moved)).unwrap().index = old_index;
}
@ -467,13 +467,13 @@ impl World {
let target_index = target_arch.allocate(entity.id());
loc.archetype = target;
loc.index = target_index;
if let Some(moved) = source_arch.move_to(old_index, |src, ty, size, is_added, is_modified| {
if let Some(moved) = source_arch.move_to(old_index, |src, ty, size, is_added, is_mutated| {
// Only move the components present in the target archetype, i.e. the non-removed ones.
if let Some(dst) = target_arch.get_dynamic(ty, size, target_index) {
ptr::copy_nonoverlapping(src, dst.as_ptr(), size);
let state = target_arch.get_type_state_mut(ty).unwrap();
state.added_entities[target_index as usize] = is_added;
state.modified_entities[target_index as usize] = is_modified;
state.mutated_entities[target_index as usize] = is_mutated;
}
}) {
self.entities.get_mut(Entity::with_id(moved)).unwrap().index = old_index;
@ -567,7 +567,7 @@ impl World {
self.entities.get(entity).ok()
}
/// Clears each entity's tracker state. For example, each entity's component "modified" state will be reset to `false`.
/// Clears each entity's tracker state. For example, each entity's component "mutated" state will be reset to `false`.
pub fn clear_trackers(&mut self) {
for archetype in self.archetypes.iter_mut() {
archetype.clear_trackers();

View File

@ -16,6 +16,6 @@ pub mod prelude {
Commands, IntoForEachSystem, IntoQuerySystem, IntoThreadLocalSystem, Query, System,
},
world::WorldBuilderSource,
Bundle, Changed, Component, Entity, Ref, RefMut, With, Without, World,
Bundle, Mutated, Component, Entity, Ref, RefMut, With, Without, World,
};
}

View File

@ -30,14 +30,14 @@ fn button_system(
button_materials: Res<ButtonMaterials>,
mut click_query: Query<(
&Button,
Changed<Click>,
Mutated<Click>,
Option<&Hover>,
&mut Handle<ColorMaterial>,
&Children,
)>,
mut hover_query: Query<(
&Button,
Changed<Hover>,
Mutated<Hover>,
Option<&Click>,
&mut Handle<ColorMaterial>,
&Children,