Skip to content

Commit

Permalink
fix #2
Browse files Browse the repository at this point in the history
fix #11
remove all direct access to storages
  • Loading branch information
leudz committed Aug 26, 2019
1 parent dd34c84 commit 1c2620a
Show file tree
Hide file tree
Showing 24 changed files with 2,501 additions and 1,548 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,11 @@ fn is_in_acid(pos: &Position) -> bool {
true
}

let world = World::default();
let world = World::new::<(Position, Health)>();

world.new_entity((Position { x: 0.0, y: 0.0 }, Health(1000.0)));
world.run::<(EntitiesMut, &mut Position, &mut Health), _>(|mut entities, mut pos, mut health| {
entities.add_entity((&mut pos, &mut health), Position { x: 0.0, y: 0.0 }, Health(1000.0));
});

world.add_workload("In acid", InAcid);
world.run_default();
Expand Down
87 changes: 22 additions & 65 deletions src/atomic_refcell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,6 @@ impl BorrowState {
error::Borrow::Unique
}
}
/// Downgrades a unique Borrow to a shared Borrow.
/// # Safety
/// Has to be used with a unique borrow.
unsafe fn downgrade(&self) {
self.0.store(1, Ordering::Release);
}
}

impl Default for BorrowState {
Expand All @@ -116,18 +110,6 @@ pub enum Borrow<'a> {
Unique(&'a BorrowState),
}

impl Borrow<'_> {
pub(crate) fn downgrade(self) -> Self {
match self {
Borrow::Unique(borrow) => {
unsafe { borrow.downgrade() }
Borrow::Shared(borrow)
}
Borrow::Shared(_) => unreachable!(),
}
}
}

impl Clone for Borrow<'_> {
fn clone(&self) -> Self {
match self {
Expand Down Expand Up @@ -224,13 +206,6 @@ impl<'a, T: 'a + Sized> RefMut<'a, T> {
borrow: origin.borrow,
}
}
/// Downgrades a unique Borrow to a shared Borrow.
pub(crate) fn downgrade(RefMut { inner, borrow }: Self) -> Ref<'a, T> {
Ref {
inner,
borrow: borrow.downgrade(),
}
}
/// Get the inner parts of the `RefMut`.
/// # Safety
/// The reference has to be dropped before `Borrow`
Expand Down Expand Up @@ -265,46 +240,28 @@ impl<T: ?Sized> std::convert::AsMut<T> for RefMut<'_, T> {
}
}

#[cfg(test)]
mod test {
use super::*;
#[test]
fn reborrow() {
let refcell = AtomicRefCell::new(0);
let _first_borrow = refcell.try_borrow().unwrap();
#[test]
fn reborrow() {
let refcell = AtomicRefCell::new(0);
let _first_borrow = refcell.try_borrow().unwrap();

assert!(&refcell.try_borrow().is_ok());
assert_eq!(
std::mem::discriminant(&refcell.try_borrow_mut().err().unwrap()),
std::mem::discriminant(&error::Borrow::Shared)
);
}
#[test]
fn unique_reborrow() {
let refcell = AtomicRefCell::new(0);
let _first_borrow = refcell.try_borrow_mut().unwrap();
assert!(&refcell.try_borrow().is_ok());
assert_eq!(
std::mem::discriminant(&refcell.try_borrow_mut().err().unwrap()),
std::mem::discriminant(&error::Borrow::Shared)
);
}
#[test]
fn unique_reborrow() {
let refcell = AtomicRefCell::new(0);
let _first_borrow = refcell.try_borrow_mut().unwrap();

assert_eq!(
std::mem::discriminant(&refcell.try_borrow().err().unwrap()),
std::mem::discriminant(&error::Borrow::Unique)
);
assert_eq!(
std::mem::discriminant(&refcell.try_borrow_mut().err().unwrap()),
std::mem::discriminant(&error::Borrow::Unique)
);
}
// Checks if a downgrade change the ref type to `Ref`
// and if the borrow is `Borrow::Shared`
#[test]
fn downgrade_is_shared() {
let refcell = AtomicRefCell::new(0);
let borrow = refcell.try_borrow_mut().unwrap();
let borrow = RefMut::downgrade(borrow);
let (_, borrow) = unsafe { Ref::destructure(borrow) };
let borrow_state = BorrowState(AtomicUsize::new(1));
assert_eq!(
std::mem::discriminant(&borrow),
std::mem::discriminant(&Borrow::Shared(&borrow_state))
);
}
assert_eq!(
std::mem::discriminant(&refcell.try_borrow().err().unwrap()),
std::mem::discriminant(&error::Borrow::Unique)
);
assert_eq!(
std::mem::discriminant(&refcell.try_borrow_mut().err().unwrap()),
std::mem::discriminant(&error::Borrow::Unique)
);
}
38 changes: 17 additions & 21 deletions src/component_storage/hasher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,23 @@ impl Hasher for TypeIdHasher {
}
}

#[cfg(test)]
mod test {
use super::*;
#[test]
fn hasher() {
fn verify<T: 'static + ?Sized>() {
use std::any::TypeId;
use std::hash::Hash;
#[test]
fn hasher() {
fn verify<T: 'static + ?Sized>() {
use std::any::TypeId;
use std::hash::Hash;

let mut hasher = TypeIdHasher::default();
let type_id = TypeId::of::<T>();
type_id.hash(&mut hasher);
assert_eq!(hasher.finish(), unsafe {
std::mem::transmute::<TypeId, u64>(type_id)
});
}

verify::<usize>();
verify::<()>();
verify::<str>();
verify::<&'static str>();
verify::<[u8; 20]>();
let mut hasher = TypeIdHasher::default();
let type_id = TypeId::of::<T>();
type_id.hash(&mut hasher);
assert_eq!(hasher.finish(), unsafe {
std::mem::transmute::<TypeId, u64>(type_id)
});
}

verify::<usize>();
verify::<()>();
verify::<str>();
verify::<&'static str>();
verify::<[u8; 20]>();
}
104 changes: 55 additions & 49 deletions src/component_storage/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
mod delete;
mod hasher;
mod view;

use crate::atomic_refcell::{AtomicRefCell, Ref, RefMut};
use crate::entity::Key;
use crate::error;
use crate::sparse_array::SparseArray;
use delete::Delete;
use crate::unknown_storage::UnknownStorage;
use hasher::TypeIdHasher;
use std::any::{Any, TypeId};
use std::collections::HashMap;
Expand All @@ -15,24 +14,24 @@ pub(crate) use view::AllStoragesViewMut;

/// Abstract away `T` from `SparseArray<T>` to be able to store
/// different types in a `HashMap<TypeId, ComponentStorage>`.
/// `delete` is the address of the vtable part of the `SparseArray`'s `Delete` implementation.
/// `unknown` is the address of the vtable part of the `SparseArray`'s `UnknownStorage` implementation.
pub(crate) struct ComponentStorage {
data: AtomicRefCell<Box<dyn Any + Send + Sync>>,
delete: usize,
unknown: usize,
}

impl ComponentStorage {
/// Creates a new `ComponentStorage` storing elements of type T.
pub(crate) fn new<T: 'static + Send + Sync>() -> Self {
let array = SparseArray::<T>::default();
// store the vtable of this trait object
// for a full explanation see Delete documentation
let delete: [usize; 2] = unsafe {
*(&(&array as &dyn Delete as *const _) as *const *const _ as *const [usize; 2])
// for a full explanation see UnknownStorage documentation
let unknown: [usize; 2] = unsafe {
*(&(&array as &dyn UnknownStorage as *const _) as *const *const _ as *const [usize; 2])
};
ComponentStorage {
data: AtomicRefCell::new(Box::new(array)),
delete: delete[1],
unknown: unknown[1],
}
}
/// Immutably borrows the container.
Expand All @@ -52,14 +51,25 @@ impl ComponentStorage {
}))
}
/// Mutably borrows the container and delete `index`.
pub(crate) fn delete(&mut self, entity: Key) -> Result<(), error::Borrow> {
// reconstruct a `dyn Delete` from two pointers
// for a full explanation see Delete documentation
pub(crate) fn delete(&mut self, entity: Key) -> Result<&[TypeId], error::Borrow> {
// reconstruct a `dyn UnknownStorage` from two pointers
// for a full explanation see UnknownStorage documentation
let array: RefMut<Box<dyn Any + Send + Sync>> = self.data.try_borrow_mut()?;
let array: usize = &**array as *const dyn Any as *const () as usize;
let delete: &mut dyn Delete =
unsafe { &mut **(&[array, self.delete] as *const _ as *const *mut dyn Delete) };
delete.delete(entity);
let unknown: &mut dyn UnknownStorage = unsafe {
&mut **(&[array, self.unknown] as *const _ as *const *mut dyn UnknownStorage)
};
Ok(unknown.delete(entity))
}
pub(crate) fn unpack(&mut self, entity: Key) -> Result<(), error::Borrow> {
// reconstruct a `dyn UnknownStorage` from two pointers
// for a full explanation see UnknownStorage documentation
let array: RefMut<Box<dyn Any + Send + Sync>> = self.data.try_borrow_mut()?;
let array: usize = &**array as *const dyn Any as *const () as usize;
let unknown: &mut dyn UnknownStorage = unsafe {
&mut **(&[array, self.unknown] as *const _ as *const *mut dyn UnknownStorage)
};
unknown.unpack(entity);
Ok(())
}
}
Expand All @@ -84,39 +94,35 @@ impl AllStorages {
}
}

#[cfg(test)]
mod test {
use super::*;
#[test]
fn delete() {
let mut storage = ComponentStorage::new::<&'static str>();
let mut key = Key::zero();
key.set_index(5);
storage.array_mut().unwrap().view_mut().insert("test5", key);
key.set_index(10);
storage
.array_mut()
.unwrap()
.view_mut()
.insert("test10", key);
key.set_index(1);
storage.array_mut().unwrap().view_mut().insert("test1", key);
key.set_index(5);
storage.delete(key).unwrap();
assert_eq!(storage.array::<&str>().unwrap().get(key), None);
key.set_index(10);
assert_eq!(storage.array::<&str>().unwrap().get(key), Some(&"test10"));
key.set_index(1);
assert_eq!(storage.array::<&str>().unwrap().get(key), Some(&"test1"));
key.set_index(10);
storage.delete(key).unwrap();
key.set_index(1);
storage.delete(key).unwrap();
key.set_index(5);
assert_eq!(storage.array::<&str>().unwrap().get(key), None);
key.set_index(10);
assert_eq!(storage.array::<&str>().unwrap().get(key), None);
key.set_index(1);
assert_eq!(storage.array::<&str>().unwrap().get(key), None);
}
#[test]
fn delete() {
let mut storage = ComponentStorage::new::<&'static str>();
let mut key = Key::zero();
key.set_index(5);
storage.array_mut().unwrap().view_mut().insert("test5", key);
key.set_index(10);
storage
.array_mut()
.unwrap()
.view_mut()
.insert("test10", key);
key.set_index(1);
storage.array_mut().unwrap().view_mut().insert("test1", key);
key.set_index(5);
storage.delete(key).unwrap();
assert_eq!(storage.array::<&str>().unwrap().get(key), None);
key.set_index(10);
assert_eq!(storage.array::<&str>().unwrap().get(key), Some(&"test10"));
key.set_index(1);
assert_eq!(storage.array::<&str>().unwrap().get(key), Some(&"test1"));
key.set_index(10);
storage.delete(key).unwrap();
key.set_index(1);
storage.delete(key).unwrap();
key.set_index(5);
assert_eq!(storage.array::<&str>().unwrap().get(key), None);
key.set_index(10);
assert_eq!(storage.array::<&str>().unwrap().get(key), None);
key.set_index(1);
assert_eq!(storage.array::<&str>().unwrap().get(key), None);
}
18 changes: 16 additions & 2 deletions src/component_storage/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,23 @@ pub struct AllStoragesViewMut<'a>(

impl AllStoragesViewMut<'_> {
pub(crate) fn delete(&mut self, entity: Key) {
let mut storage_to_unpack = Vec::new();
for storage in self.0.values_mut() {
storage.delete(entity).unwrap();
let observers = storage.delete(entity).unwrap();
storage_to_unpack.reserve(observers.len());
let mut i = 0;
for observer in observers.iter().copied() {
while i < storage_to_unpack.len() && observer < storage_to_unpack[i] {
i += 1;
}
if storage_to_unpack.is_empty() || observer != storage_to_unpack[i] {
storage_to_unpack.insert(i, observer);
}
}
}

for storage in storage_to_unpack {
self.0.get_mut(&storage).unwrap().unpack(entity).unwrap();
}
unimplemented!()
}
}

0 comments on commit 1c2620a

Please sign in to comment.