Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DerefFlaggedGen storage that includes the entity generation in events #725

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 20 additions & 11 deletions src/storage/deref_flagged.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use hibitset::BitSetLike;

use crate::{
storage::{ComponentEvent, DenseVecStorage, Tracked, TryDefault, UnprotectedStorage},
world::{Component, Index},
world::{Component, HasIndex, Index},
};

use shrev::EventChannel;
Expand Down Expand Up @@ -55,7 +55,12 @@ where
}

impl<C: Component, T: UnprotectedStorage<C>> UnprotectedStorage<C> for DerefFlaggedStorage<C, T> {
type AccessMut<'a> where T: 'a = FlaggedAccessMut<'a, <T as UnprotectedStorage<C>>::AccessMut<'a>, C>;
type AccessMut<'a>
where
T: 'a,
= FlaggedAccessMut<'a, <T as UnprotectedStorage<C>>::AccessMut<'a>, C>;

type MutIndex = <T as UnprotectedStorage<C>>::MutIndex;

unsafe fn clean<B>(&mut self, has: B)
where
Expand All @@ -68,27 +73,27 @@ impl<C: Component, T: UnprotectedStorage<C>> UnprotectedStorage<C> for DerefFlag
self.storage.get(id)
}

unsafe fn get_mut(&mut self, id: Index) -> Self::AccessMut<'_> {
unsafe fn get_mut(&mut self, id: Self::MutIndex) -> Self::AccessMut<'_> {
let emit = self.emit_event();
FlaggedAccessMut {
channel: &mut self.channel,
emit,
id,
id: id.id(),
access: self.storage.get_mut(id),
phantom: PhantomData,
}
}

unsafe fn insert(&mut self, id: Index, comp: C) {
unsafe fn insert(&mut self, id: Self::MutIndex, comp: C) {
if self.emit_event() {
self.channel.single_write(ComponentEvent::Inserted(id));
self.channel.single_write(ComponentEvent::Inserted(id.id()));
}
self.storage.insert(id, comp);
}

unsafe fn remove(&mut self, id: Index) -> C {
unsafe fn remove(&mut self, id: Self::MutIndex) -> C {
if self.emit_event() {
self.channel.single_write(ComponentEvent::Removed(id));
self.channel.single_write(ComponentEvent::Removed(id.id()));
}
self.storage.remove(id)
}
Expand Down Expand Up @@ -123,14 +128,18 @@ pub struct FlaggedAccessMut<'a, A, C> {
}

impl<'a, A, C> Deref for FlaggedAccessMut<'a, A, C>
where A: Deref<Target = C>
where
A: Deref<Target = C>,
{
type Target = C;
fn deref(&self) -> &Self::Target { self.access.deref() }
fn deref(&self) -> &Self::Target {
self.access.deref()
}
}

impl<'a, A, C> DerefMut for FlaggedAccessMut<'a, A, C>
where A: DerefMut<Target = C>
where
A: DerefMut<Target = C>,
{
fn deref_mut(&mut self) -> &mut Self::Target {
if self.emit {
Expand Down
155 changes: 155 additions & 0 deletions src/storage/deref_flagged_gen.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
use std::{
marker::PhantomData,
ops::{Deref, DerefMut},
};

use hibitset::BitSetLike;

use crate::{
storage::{ComponentEvent, DenseVecStorage, Tracked, TryDefault, UnprotectedStorage},
world::{Component, HasIndex, Index},
Entity,
};

use shrev::EventChannel;

/// Wrapper storage that tracks modifications, insertions, and removals of
/// components through an `EventChannel`, in a similar manner to `FlaggedStorage`.
///
/// Unlike `FlaggedStorage`, this storage uses a wrapper type for mutable
/// accesses that only emits modification events when the component is actually
/// used mutably. This means that simply performing a mutable join or calling
/// `WriteStorage::get_mut` will not, by itself, trigger a modification event.
pub struct DerefFlaggedGenStorage<C, T = DenseVecStorage<C>> {
channel: EventChannel<ComponentEvent<Entity>>,
storage: T,
#[cfg(feature = "storage-event-control")]
event_emission: bool,
phantom: PhantomData<C>,
}

impl<C, T> DerefFlaggedGenStorage<C, T> {
#[cfg(feature = "storage-event-control")]
fn emit_event(&self) -> bool {
self.event_emission
}

#[cfg(not(feature = "storage-event-control"))]
fn emit_event(&self) -> bool {
true
}
}

impl<C, T> Default for DerefFlaggedGenStorage<C, T>
where
T: TryDefault,
{
fn default() -> Self {
Self {
channel: EventChannel::<ComponentEvent<Entity>>::default(),
storage: T::unwrap_default(),
#[cfg(feature = "storage-event-control")]
event_emission: true,
phantom: PhantomData,
}
}
}

impl<C: Component, T: UnprotectedStorage<C>> UnprotectedStorage<C>
for DerefFlaggedGenStorage<C, T>
{
type AccessMut<'a>
where
T: 'a,
= FlaggedAccessMut<'a, <T as UnprotectedStorage<C>>::AccessMut<'a>, C>;

type MutIndex = Entity;

unsafe fn clean<B>(&mut self, has: B)
where
B: BitSetLike,
{
self.storage.clean(has);
}

unsafe fn get(&self, id: Index) -> &C {
self.storage.get(id)
}

unsafe fn get_mut(&mut self, id: Self::MutIndex) -> Self::AccessMut<'_> {
let emit = self.emit_event();
FlaggedAccessMut {
channel: &mut self.channel,
emit,
id,
access: self.storage.get_mut(HasIndex::from_entity(id)),
phantom: PhantomData,
}
}

unsafe fn insert(&mut self, id: Self::MutIndex, comp: C) {
if self.emit_event() {
self.channel.single_write(ComponentEvent::Inserted(id));
}
self.storage.insert(HasIndex::from_entity(id), comp);
}

unsafe fn remove(&mut self, id: Self::MutIndex) -> C {
if self.emit_event() {
self.channel.single_write(ComponentEvent::Removed(id));
}
self.storage.remove(HasIndex::from_entity(id))
}
}

impl<C, T> Tracked for DerefFlaggedGenStorage<C, T> {
type Entity = Entity;

fn channel(&self) -> &EventChannel<ComponentEvent<Self::Entity>> {
&self.channel
}

fn channel_mut(&mut self) -> &mut EventChannel<ComponentEvent<Self::Entity>> {
&mut self.channel
}

#[cfg(feature = "storage-event-control")]
fn set_event_emission(&mut self, emit: bool) {
self.event_emission = emit;
}

#[cfg(feature = "storage-event-control")]
fn event_emission(&self) -> bool {
self.event_emission
}
}

pub struct FlaggedAccessMut<'a, A, C> {
channel: &'a mut EventChannel<ComponentEvent<Entity>>,
emit: bool,
id: Entity,
access: A,
phantom: PhantomData<C>,
}

impl<'a, A, C> Deref for FlaggedAccessMut<'a, A, C>
where
A: Deref<Target = C>,
{
type Target = C;
fn deref(&self) -> &Self::Target {
self.access.deref()
}
}

impl<'a, A, C> DerefMut for FlaggedAccessMut<'a, A, C>
where
A: DerefMut<Target = C>,
{
fn deref_mut(&mut self) -> &mut Self::Target {
if self.emit {
self.channel.single_write(ComponentEvent::Modified(self.id));
}
self.access.deref_mut()
}
}
25 changes: 24 additions & 1 deletion src/storage/drain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,17 @@ use crate::{
world::{Component, Index},
};

#[cfg(feature = "nightly")]
use crate::world::{EntitiesRes, HasIndex};

/// A draining storage wrapper which has a `Join` implementation
/// that removes the components.
pub struct Drain<'a, T: Component> {
/// The masked storage
pub data: &'a mut MaskedStorage<T>,
/// Entities to get the generation for component events
#[cfg(feature = "nightly")]
pub entities: &'a EntitiesRes,
}

impl<'a, T> Join for Drain<'a, T>
Expand All @@ -19,15 +25,32 @@ where
{
type Mask = BitSet;
type Type = T;
#[cfg(feature = "nightly")]
type Value = (&'a mut MaskedStorage<T>, &'a EntitiesRes);
#[cfg(not(feature = "nightly"))]
type Value = &'a mut MaskedStorage<T>;

// SAFETY: No invariants to meet and no unsafe code.
unsafe fn open(self) -> (Self::Mask, Self::Value) {
let mask = self.data.mask.clone();

(mask, self.data)
#[cfg(feature = "nightly")]
let t = (mask, (self.data, self.entities));
#[cfg(not(feature = "nightly"))]
let t = (mask, self.data);

t
}

// SAFETY: No invariants to meet and no unsafe code.
#[cfg(feature = "nightly")]
unsafe fn get((storage, entities): &mut Self::Value, id: Index) -> T {
storage
.remove(HasIndex::from_index(id, entities))
.expect("Tried to access same index twice")
}

#[cfg(not(feature = "nightly"))]
// SAFETY: No invariants to meet and no unsafe code.
unsafe fn get(value: &mut Self::Value, id: Index) -> T {
value.remove(id).expect("Tried to access same index twice")
Expand Down
26 changes: 20 additions & 6 deletions src/storage/entry.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use hibitset::BitSetAll;

use super::*;
use super::*; // TODO: remove glob
use crate::join::Join;

impl<'e, T, D> Storage<'e, T, D>
Expand Down Expand Up @@ -194,15 +194,25 @@ where
pub fn get_mut(&mut self) -> AccessMutReturn<'_, T> {
// SAFETY: This is safe since `OccupiedEntry` is only constructed
// after checking the mask.
unsafe { self.storage.data.inner.get_mut(self.id) }
unsafe {
self.storage
.data
.inner
.get_mut(HasIndex::from_index(self.id, &self.storage.entities))
}
}

/// Converts the `OccupiedEntry` into a mutable reference bounded by
/// the storage's lifetime.
pub fn into_mut(self) -> AccessMutReturn<'a, T> {
// SAFETY: This is safe since `OccupiedEntry` is only constructed
// after checking the mask.
unsafe { self.storage.data.inner.get_mut(self.id) }
unsafe {
self.storage
.data
.inner
.get_mut(HasIndex::from_index(self.id, &self.storage.entities))
}
}

/// Inserts a value into the storage and returns the old one.
Expand All @@ -213,7 +223,10 @@ where

/// Removes the component from the storage and returns it.
pub fn remove(self) -> T {
self.storage.data.remove(self.id).unwrap()
self.storage
.data
.remove(HasIndex::from_index(self.id, &self.storage.entities))
.unwrap()
}
}

Expand All @@ -232,10 +245,11 @@ where
/// Inserts a value into the storage.
pub fn insert(self, component: T) -> AccessMutReturn<'a, T> {
self.storage.data.mask.add(self.id);
let has_index = HasIndex::from_index(self.id, &self.storage.entities);
// SAFETY: This is safe since we added `self.id` to the mask.
unsafe {
self.storage.data.inner.insert(self.id, component);
self.storage.data.inner.get_mut(self.id)
self.storage.data.inner.insert(has_index, component);
self.storage.data.inner.get_mut(has_index)
}
}
}
Expand Down
Loading