| @@ -0,0 +1,238 @@ | |||||
| use std::ops::{Deref, DerefMut}; | |||||
| use hibitset::{BitIter, BitSetAll, BitSetLike}; | |||||
| use log::warn; | |||||
| use crate::{ | |||||
| entity::{Entities, Entity, Index}, | |||||
| misc::BitAnd, | |||||
| resource::{Ref, RefMut, Resource}, | |||||
| }; | |||||
| use super::{read::Read, write::Write}; | |||||
| pub trait Join { | |||||
| type Type; | |||||
| type Value; | |||||
| type Mask: BitSetLike; | |||||
| fn open(self) -> (Self::Mask, Self::Value); | |||||
| fn get(value: &mut Self::Value, index: Index) -> Self::Type; | |||||
| fn join(self) -> JoinIter<Self> | |||||
| where | |||||
| Self: Sized, | |||||
| { | |||||
| JoinIter::new(self) | |||||
| } | |||||
| fn maybe(self) -> MaybeJoin<Self> | |||||
| where | |||||
| Self: Sized, | |||||
| { | |||||
| MaybeJoin(self) | |||||
| } | |||||
| #[inline] | |||||
| fn is_unconstrained() -> bool { | |||||
| false | |||||
| } | |||||
| } | |||||
| pub struct MaybeJoin<J: Join>(pub J); | |||||
| impl<T> Join for MaybeJoin<T> | |||||
| where | |||||
| T: Join, | |||||
| { | |||||
| type Mask = BitSetAll; | |||||
| type Type = Option<<T as Join>::Type>; | |||||
| type Value = (<T as Join>::Mask, <T as Join>::Value); | |||||
| fn open(self) -> (Self::Mask, Self::Value) { | |||||
| let (mask, value) = self.0.open(); | |||||
| (BitSetAll, (mask, value)) | |||||
| } | |||||
| fn get((mask, value): &mut Self::Value, index: Index) -> Self::Type { | |||||
| if mask.contains(index) { | |||||
| Some(<T as Join>::get(value, index)) | |||||
| } else { | |||||
| None | |||||
| } | |||||
| } | |||||
| fn is_unconstrained() -> bool { | |||||
| true | |||||
| } | |||||
| } | |||||
| pub struct JoinIter<J: Join> { | |||||
| keys: BitIter<J::Mask>, | |||||
| values: J::Value, | |||||
| } | |||||
| impl<J: Join> JoinIter<J> { | |||||
| pub fn new(j: J) -> Self { | |||||
| if <J as Join>::is_unconstrained() { | |||||
| warn!( | |||||
| "`Join` possibly iterating through all indices, you might've made a join with all `MaybeJoin`s, which is unbounded in length." | |||||
| ); | |||||
| } | |||||
| let (keys, values) = j.open(); | |||||
| JoinIter { | |||||
| keys: keys.iter(), | |||||
| values, | |||||
| } | |||||
| } | |||||
| pub fn get(&mut self, entity: Entity, entities: &Entities) -> Option<J::Type> { | |||||
| if self.keys.contains(entity.index()) && entities.is_alive(entity) { | |||||
| Some(J::get(&mut self.values, entity.index())) | |||||
| } else { | |||||
| None | |||||
| } | |||||
| } | |||||
| } | |||||
| impl<J: Join> std::iter::Iterator for JoinIter<J> { | |||||
| type Item = J::Type; | |||||
| fn next(&mut self) -> Option<J::Type> { | |||||
| self.keys.next().map(|idx| J::get(&mut self.values, idx)) | |||||
| } | |||||
| } | |||||
| impl<J: Join> Clone for JoinIter<J> | |||||
| where | |||||
| J::Mask: Clone, | |||||
| J::Value: Clone, | |||||
| { | |||||
| fn clone(&self) -> Self { | |||||
| Self { | |||||
| keys: self.keys.clone(), | |||||
| values: self.values.clone(), | |||||
| } | |||||
| } | |||||
| } | |||||
| macro_rules! define_tuple_join { | |||||
| ($($from:ident),*) => { | |||||
| impl<$($from,)*> Join for ($($from),*,) | |||||
| where $($from: Join),*, | |||||
| ($(<$from as Join>::Mask,)*): BitAnd, | |||||
| { | |||||
| type Type = ($($from::Type),*,); | |||||
| type Value = ($($from::Value),*,); | |||||
| type Mask = <($($from::Mask,)*) as BitAnd>::Value; | |||||
| #[allow(non_snake_case)] | |||||
| fn open(self) -> (Self::Mask, Self::Value) { | |||||
| let ($($from,)*) = self; | |||||
| let ($($from,)*) = ($($from.open(),)*); | |||||
| ( | |||||
| ($($from.0),*,).and(), | |||||
| ($($from.1),*,) | |||||
| ) | |||||
| } | |||||
| #[allow(non_snake_case)] | |||||
| fn get(v: &mut Self::Value, i: Index) -> Self::Type { | |||||
| let &mut ($(ref mut $from,)*) = v; | |||||
| ($($from::get($from, i),)*) | |||||
| } | |||||
| #[inline] | |||||
| fn is_unconstrained() -> bool { | |||||
| let mut unconstrained = true; | |||||
| $( unconstrained = unconstrained && $from::is_unconstrained(); )* | |||||
| unconstrained | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| define_tuple_join! { A } | |||||
| define_tuple_join! { A, B } | |||||
| define_tuple_join! { A, B, C } | |||||
| define_tuple_join! { A, B, C, D } | |||||
| define_tuple_join! { A, B, C, D, E } | |||||
| define_tuple_join! { A, B, C, D, E, F } | |||||
| define_tuple_join! { A, B, C, D, E, F, G } | |||||
| define_tuple_join! { A, B, C, D, E, F, G, H } | |||||
| define_tuple_join! { A, B, C, D, E, F, G, H, I } | |||||
| define_tuple_join! { A, B, C, D, E, F, G, H, I, J } | |||||
| define_tuple_join! { A, B, C, D, E, F, G, H, I, J, K } | |||||
| define_tuple_join! { A, B, C, D, E, F, G, H, I, J, K, L } | |||||
| define_tuple_join! { A, B, C, D, E, F, G, H, I, J, K, L, M } | |||||
| define_tuple_join! { A, B, C, D, E, F, G, H, I, J, K, L, M, N } | |||||
| define_tuple_join! { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O } | |||||
| define_tuple_join! { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P } | |||||
| macro_rules! define_mutable_join { | |||||
| ($ty:ty) => { | |||||
| impl<'a, 'b, T> Join for &'a mut $ty | |||||
| where | |||||
| &'a mut T: Join, | |||||
| T: Resource, | |||||
| { | |||||
| type Type = <&'a mut T as Join>::Type; | |||||
| type Value = <&'a mut T as Join>::Value; | |||||
| type Mask = <&'a mut T as Join>::Mask; | |||||
| fn open(self) -> (Self::Mask, Self::Value) { | |||||
| self.deref_mut().open() | |||||
| } | |||||
| fn get(v: &mut Self::Value, i: Index) -> Self::Type { | |||||
| <&'a mut T as Join>::get(v, i) | |||||
| } | |||||
| #[inline] | |||||
| fn is_unconstrained() -> bool { | |||||
| <&'a mut T as Join>::is_unconstrained() | |||||
| } | |||||
| } | |||||
| }; | |||||
| } | |||||
| define_mutable_join!(Write<'b, T>); | |||||
| define_mutable_join!(RefMut<'b, T>); | |||||
| macro_rules! define_immutable_join { | |||||
| ($ty:ty) => { | |||||
| impl<'a, 'b, T> Join for &'a $ty | |||||
| where | |||||
| &'a T: Join, | |||||
| T: Resource, | |||||
| { | |||||
| type Type = <&'a T as Join>::Type; | |||||
| type Value = <&'a T as Join>::Value; | |||||
| type Mask = <&'a T as Join>::Mask; | |||||
| fn open(self) -> (Self::Mask, Self::Value) { | |||||
| self.deref().open() | |||||
| } | |||||
| fn get(v: &mut Self::Value, i: Index) -> Self::Type { | |||||
| <&'a T as Join>::get(v, i) | |||||
| } | |||||
| #[inline] | |||||
| fn is_unconstrained() -> bool { | |||||
| <&'a T as Join>::is_unconstrained() | |||||
| } | |||||
| } | |||||
| }; | |||||
| } | |||||
| define_immutable_join!(Read<'b, T>); | |||||
| define_immutable_join!(Ref<'b, T>); | |||||
| @@ -1,10 +1,12 @@ | |||||
| pub mod accessor; | pub mod accessor; | ||||
| pub mod join; | |||||
| pub mod read; | pub mod read; | ||||
| pub mod read_storage; | pub mod read_storage; | ||||
| pub mod write; | pub mod write; | ||||
| pub mod write_storage; | pub mod write_storage; | ||||
| pub use accessor::{Accessor, AccessorCow, AccessorType, StaticAccessor}; | pub use accessor::{Accessor, AccessorCow, AccessorType, StaticAccessor}; | ||||
| pub use join::Join; | |||||
| pub use read::Read; | pub use read::Read; | ||||
| pub use read_storage::ReadStorage; | pub use read_storage::ReadStorage; | ||||
| pub use write::Write; | pub use write::Write; | ||||
| @@ -11,13 +11,12 @@ pub async fn execute( | |||||
| ) { | ) { | ||||
| info!("System started: {}", &name); | info!("System started: {}", &name); | ||||
| run(&name, dispatchable, sender, receivers, world).await; | |||||
| run(dispatchable, sender, receivers, world).await; | |||||
| info!("System finished: {}", &name); | info!("System finished: {}", &name); | ||||
| } | } | ||||
| async fn run( | async fn run( | ||||
| name: &str, | |||||
| mut dispatchable: BoxedDispatchable, | mut dispatchable: BoxedDispatchable, | ||||
| sender: Sender, | sender: Sender, | ||||
| mut receivers: Vec<Receiver>, | mut receivers: Vec<Receiver>, | ||||
| @@ -31,8 +30,6 @@ async fn run( | |||||
| } | } | ||||
| } | } | ||||
| info!("Run system: {}", &name); | |||||
| let world = world.borrow(); | let world = world.borrow(); | ||||
| let world = world.as_ref().unwrap(); | let world = world.as_ref().unwrap(); | ||||
| @@ -11,7 +11,7 @@ pub mod storage; | |||||
| pub mod system; | pub mod system; | ||||
| pub mod world; | pub mod world; | ||||
| pub use access::{ReadStorage, WriteStorage}; | |||||
| pub use access::{Join, ReadStorage, WriteStorage}; | |||||
| pub use dispatcher::Dispatcher; | pub use dispatcher::Dispatcher; | ||||
| pub use resource::Resources; | pub use resource::Resources; | ||||
| pub use storage::VecStorage; | pub use storage::VecStorage; | ||||
| @@ -2,7 +2,7 @@ use std::io::Error as IoError; | |||||
| use std::time::{Duration, Instant}; | use std::time::{Duration, Instant}; | ||||
| use async_ecs::{ | use async_ecs::{ | ||||
| dispatcher::Error as DispatcherError, Dispatcher, ReadStorage, System, VecStorage, World, | |||||
| dispatcher::Error as DispatcherError, Dispatcher, Join, ReadStorage, System, VecStorage, World, | |||||
| WriteStorage, | WriteStorage, | ||||
| }; | }; | ||||
| use async_ecs_derive::Component; | use async_ecs_derive::Component; | ||||
| @@ -137,9 +137,11 @@ impl Acceleration { | |||||
| impl<'a> System<'a> for Move { | impl<'a> System<'a> for Move { | ||||
| type SystemData = (WriteStorage<'a, Position>, ReadStorage<'a, Velocity>); | type SystemData = (WriteStorage<'a, Position>, ReadStorage<'a, Velocity>); | ||||
| fn run(&mut self, (position, velocity): Self::SystemData) { | |||||
| let _position = position; | |||||
| let _velocity = velocity; | |||||
| fn run(&mut self, (mut position, velocity): Self::SystemData) { | |||||
| for (position, velocity) in (&mut position, &velocity).join() { | |||||
| position.x += velocity.x; | |||||
| position.y += velocity.y; | |||||
| } | |||||
| /* | /* | ||||
| use specs::{prelude::ParallelIterator, ParJoin}; | use specs::{prelude::ParallelIterator, ParJoin}; | ||||
| @@ -157,9 +159,11 @@ impl<'a> System<'a> for Move { | |||||
| impl<'a> System<'a> for Accelerate { | impl<'a> System<'a> for Accelerate { | ||||
| type SystemData = (WriteStorage<'a, Velocity>, ReadStorage<'a, Acceleration>); | type SystemData = (WriteStorage<'a, Velocity>, ReadStorage<'a, Acceleration>); | ||||
| fn run(&mut self, (velocity, acceleration): Self::SystemData) { | |||||
| let _velocity = velocity; | |||||
| let _acceleration = acceleration; | |||||
| fn run(&mut self, (mut velocity, acceleration): Self::SystemData) { | |||||
| for (velocity, acceleration) in (&mut velocity, &acceleration).join() { | |||||
| velocity.x += acceleration.x; | |||||
| velocity.y += acceleration.y; | |||||
| } | |||||
| /* | /* | ||||
| use specs::{prelude::ParallelIterator, ParJoin}; | use specs::{prelude::ParallelIterator, ParJoin}; | ||||
| @@ -0,0 +1,55 @@ | |||||
| use hibitset::{BitSetAnd, BitSetLike}; | |||||
| use crate::misc::Split; | |||||
| pub trait BitAnd { | |||||
| type Value: BitSetLike; | |||||
| fn and(self) -> Self::Value; | |||||
| } | |||||
| impl<A> BitAnd for (A,) | |||||
| where | |||||
| A: BitSetLike, | |||||
| { | |||||
| type Value = A; | |||||
| fn and(self) -> Self::Value { | |||||
| self.0 | |||||
| } | |||||
| } | |||||
| macro_rules! bitset_and { | |||||
| ($($from:ident),*) => { | |||||
| impl<$($from),*> BitAnd for ($($from),*) | |||||
| where $($from: BitSetLike),* | |||||
| { | |||||
| type Value = BitSetAnd< | |||||
| <<Self as Split>::Left as BitAnd>::Value, | |||||
| <<Self as Split>::Right as BitAnd>::Value | |||||
| >; | |||||
| fn and(self) -> Self::Value { | |||||
| let (l, r) = self.split(); | |||||
| BitSetAnd(l.and(), r.and()) | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| bitset_and! { A, B } | |||||
| bitset_and! { A, B, C } | |||||
| bitset_and! { A, B, C, D } | |||||
| bitset_and! { A, B, C, D, E } | |||||
| bitset_and! { A, B, C, D, E, F } | |||||
| bitset_and! { A, B, C, D, E, F, G } | |||||
| bitset_and! { A, B, C, D, E, F, G, H } | |||||
| bitset_and! { A, B, C, D, E, F, G, H, I } | |||||
| bitset_and! { A, B, C, D, E, F, G, H, I, J } | |||||
| bitset_and! { A, B, C, D, E, F, G, H, I, J, K } | |||||
| bitset_and! { A, B, C, D, E, F, G, H, I, J, K, L } | |||||
| bitset_and! { A, B, C, D, E, F, G, H, I, J, K, L, M } | |||||
| bitset_and! { A, B, C, D, E, F, G, H, I, J, K, L, M, N } | |||||
| bitset_and! { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O } | |||||
| bitset_and! { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P } | |||||
| @@ -1,3 +1,7 @@ | |||||
| pub mod bit_and; | |||||
| pub mod split; | |||||
| pub mod try_default; | pub mod try_default; | ||||
| pub use bit_and::BitAnd; | |||||
| pub use split::Split; | |||||
| pub use try_default::TryDefault; | pub use try_default::TryDefault; | ||||
| @@ -0,0 +1,47 @@ | |||||
| pub trait Split { | |||||
| type Left; | |||||
| type Right; | |||||
| fn split(self) -> (Self::Left, Self::Right); | |||||
| } | |||||
| macro_rules! for_each_prefix ( | |||||
| ($m:ident, [$(($acc:tt),)*], []) => { | |||||
| $m!($($acc,)*); | |||||
| }; | |||||
| ($m:ident, [$(($acc:tt),)*], [($arg0:tt), $(($arg:tt),)*]) => { | |||||
| $m!($($acc,)*); | |||||
| for_each_prefix!($m, [$(($acc),)* ($arg0),], [$(($arg),)*]); | |||||
| }; | |||||
| ); | |||||
| macro_rules! split_impl ( | |||||
| ($(($a:ident, $b:ident),)*) => ( | |||||
| impl<$($a,)* $($b,)*> Split for ($($a,)* $($b,)*) { | |||||
| type Left = ($($a,)*); | |||||
| type Right = ($($b,)*); | |||||
| #[allow(non_snake_case)] | |||||
| fn split(self) -> (Self::Left, Self::Right) { | |||||
| match self { | |||||
| ($($a,)* $($b,)*) => (($($a,)*), ($($b,)*)) | |||||
| } | |||||
| } | |||||
| } | |||||
| impl<$($a,)* $($b,)* TLast> Split for ($($a,)* $($b,)* TLast,) { | |||||
| type Left = ($($a,)*); | |||||
| type Right = ($($b,)* TLast,); | |||||
| #[allow(non_snake_case)] | |||||
| fn split(self) -> (Self::Left, Self::Right) { | |||||
| match self { | |||||
| ($($a,)* $($b,)* t_last,) => (($($a,)*), ($($b,)* t_last,)) | |||||
| } | |||||
| } | |||||
| } | |||||
| ); | |||||
| ); | |||||
| for_each_prefix! { | |||||
| split_impl, | |||||
| [], | |||||
| [((T0, T1)), ((T2, T3)), ((T4, T5)), ((T6, T7)), ((T8, T9)), ((T10, T11)), ((T12, T13)), ((T14, T15)),] | |||||
| } | |||||
| @@ -5,8 +5,8 @@ use hibitset::BitSet; | |||||
| use crate::{component::Component, entity::Entity, storage::Storage}; | use crate::{component::Component, entity::Entity, storage::Storage}; | ||||
| pub struct MaskedStorage<T: Component> { | pub struct MaskedStorage<T: Component> { | ||||
| mask: BitSet, | |||||
| inner: T::Storage, | |||||
| pub(crate) mask: BitSet, | |||||
| pub(crate) inner: T::Storage, | |||||
| } | } | ||||
| impl<T: Component> MaskedStorage<T> { | impl<T: Component> MaskedStorage<T> { | ||||
| @@ -17,6 +17,10 @@ impl<T: Component> MaskedStorage<T> { | |||||
| } | } | ||||
| } | } | ||||
| pub fn open_mut(&mut self) -> (&BitSet, &mut T::Storage) { | |||||
| (&self.mask, &mut self.inner) | |||||
| } | |||||
| pub fn insert(&mut self, entity: Entity, mut component: T) -> Option<T> { | pub fn insert(&mut self, entity: Entity, mut component: T) -> Option<T> { | ||||
| let index = entity.index(); | let index = entity.index(); | ||||
| @@ -1,20 +1,27 @@ | |||||
| use std::marker::PhantomData; | use std::marker::PhantomData; | ||||
| use std::ops::DerefMut; | |||||
| use std::ops::{Deref, DerefMut, Not}; | |||||
| use hibitset::{BitSet, BitSetNot}; | |||||
| use crate::{ | use crate::{ | ||||
| access::Join, | |||||
| component::Component, | component::Component, | ||||
| entity::{Entities, Entity}, | |||||
| entity::{Entities, Entity, Index}, | |||||
| error::Error, | error::Error, | ||||
| resource::Ref, | resource::Ref, | ||||
| storage::MaskedStorage, | storage::MaskedStorage, | ||||
| }; | }; | ||||
| use super::Storage; | |||||
| pub struct StorageWrapper<'a, T, D> { | pub struct StorageWrapper<'a, T, D> { | ||||
| data: D, | data: D, | ||||
| entities: Ref<'a, Entities>, | entities: Ref<'a, Entities>, | ||||
| phantom: PhantomData<T>, | phantom: PhantomData<T>, | ||||
| } | } | ||||
| pub struct AntiStorage<'a>(pub &'a BitSet); | |||||
| impl<'a, T, D> StorageWrapper<'a, T, D> { | impl<'a, T, D> StorageWrapper<'a, T, D> { | ||||
| pub fn new(data: D, entities: Ref<'a, Entities>) -> Self { | pub fn new(data: D, entities: Ref<'a, Entities>) -> Self { | ||||
| Self { | Self { | ||||
| @@ -37,4 +44,71 @@ where | |||||
| Ok(self.data.insert(entity, component)) | Ok(self.data.insert(entity, component)) | ||||
| } | } | ||||
| pub fn not(&self) -> AntiStorage<'_> { | |||||
| AntiStorage(&self.data.mask) | |||||
| } | |||||
| } | |||||
| impl<'a, 'e, T, D> Not for &'a StorageWrapper<'e, T, D> | |||||
| where | |||||
| T: Component, | |||||
| D: Deref<Target = MaskedStorage<T>>, | |||||
| { | |||||
| type Output = AntiStorage<'a>; | |||||
| fn not(self) -> Self::Output { | |||||
| AntiStorage(&self.data.mask) | |||||
| } | |||||
| } | |||||
| impl<'a, 'e, T, D> Join for &'a StorageWrapper<'e, T, D> | |||||
| where | |||||
| T: Component, | |||||
| D: Deref<Target = MaskedStorage<T>>, | |||||
| { | |||||
| type Mask = &'a BitSet; | |||||
| type Type = &'a T; | |||||
| type Value = &'a T::Storage; | |||||
| fn open(self) -> (Self::Mask, Self::Value) { | |||||
| (&self.data.mask, &self.data.inner) | |||||
| } | |||||
| fn get(v: &mut Self::Value, i: Index) -> &'a T { | |||||
| v.get(i) | |||||
| } | |||||
| } | |||||
| impl<'a, 'e, T, D> Join for &'a mut StorageWrapper<'e, T, D> | |||||
| where | |||||
| T: Component, | |||||
| D: DerefMut<Target = MaskedStorage<T>>, | |||||
| { | |||||
| type Mask = &'a BitSet; | |||||
| type Type = &'a mut T; | |||||
| type Value = &'a mut T::Storage; | |||||
| fn open(self) -> (Self::Mask, Self::Value) { | |||||
| self.data.open_mut() | |||||
| } | |||||
| fn get(v: &mut Self::Value, i: Index) -> &'a mut T { | |||||
| // HACK | |||||
| let value: *mut Self::Value = v as *mut Self::Value; | |||||
| unsafe { (*value).get_mut(i) } | |||||
| } | |||||
| } | |||||
| impl<'a> Join for AntiStorage<'a> { | |||||
| type Mask = BitSetNot<&'a BitSet>; | |||||
| type Type = (); | |||||
| type Value = (); | |||||
| fn open(self) -> (Self::Mask, ()) { | |||||
| (BitSetNot(self.0), ()) | |||||
| } | |||||
| fn get(_: &mut (), _: Index) {} | |||||
| } | } | ||||