| @@ -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 join; | |||
| pub mod read; | |||
| pub mod read_storage; | |||
| pub mod write; | |||
| pub mod write_storage; | |||
| pub use accessor::{Accessor, AccessorCow, AccessorType, StaticAccessor}; | |||
| pub use join::Join; | |||
| pub use read::Read; | |||
| pub use read_storage::ReadStorage; | |||
| pub use write::Write; | |||
| @@ -11,13 +11,12 @@ pub async fn execute( | |||
| ) { | |||
| info!("System started: {}", &name); | |||
| run(&name, dispatchable, sender, receivers, world).await; | |||
| run(dispatchable, sender, receivers, world).await; | |||
| info!("System finished: {}", &name); | |||
| } | |||
| async fn run( | |||
| name: &str, | |||
| mut dispatchable: BoxedDispatchable, | |||
| sender: Sender, | |||
| mut receivers: Vec<Receiver>, | |||
| @@ -31,8 +30,6 @@ async fn run( | |||
| } | |||
| } | |||
| info!("Run system: {}", &name); | |||
| let world = world.borrow(); | |||
| let world = world.as_ref().unwrap(); | |||
| @@ -11,7 +11,7 @@ pub mod storage; | |||
| pub mod system; | |||
| pub mod world; | |||
| pub use access::{ReadStorage, WriteStorage}; | |||
| pub use access::{Join, ReadStorage, WriteStorage}; | |||
| pub use dispatcher::Dispatcher; | |||
| pub use resource::Resources; | |||
| pub use storage::VecStorage; | |||
| @@ -2,7 +2,7 @@ use std::io::Error as IoError; | |||
| use std::time::{Duration, Instant}; | |||
| use async_ecs::{ | |||
| dispatcher::Error as DispatcherError, Dispatcher, ReadStorage, System, VecStorage, World, | |||
| dispatcher::Error as DispatcherError, Dispatcher, Join, ReadStorage, System, VecStorage, World, | |||
| WriteStorage, | |||
| }; | |||
| use async_ecs_derive::Component; | |||
| @@ -137,9 +137,11 @@ impl Acceleration { | |||
| impl<'a> System<'a> for Move { | |||
| 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}; | |||
| @@ -157,9 +159,11 @@ impl<'a> System<'a> for Move { | |||
| impl<'a> System<'a> for Accelerate { | |||
| 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}; | |||
| @@ -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 use bit_and::BitAnd; | |||
| pub use split::Split; | |||
| 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}; | |||
| pub struct MaskedStorage<T: Component> { | |||
| mask: BitSet, | |||
| inner: T::Storage, | |||
| pub(crate) mask: BitSet, | |||
| pub(crate) inner: T::Storage, | |||
| } | |||
| 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> { | |||
| let index = entity.index(); | |||
| @@ -1,20 +1,27 @@ | |||
| use std::marker::PhantomData; | |||
| use std::ops::DerefMut; | |||
| use std::ops::{Deref, DerefMut, Not}; | |||
| use hibitset::{BitSet, BitSetNot}; | |||
| use crate::{ | |||
| access::Join, | |||
| component::Component, | |||
| entity::{Entities, Entity}, | |||
| entity::{Entities, Entity, Index}, | |||
| error::Error, | |||
| resource::Ref, | |||
| storage::MaskedStorage, | |||
| }; | |||
| use super::Storage; | |||
| pub struct StorageWrapper<'a, T, D> { | |||
| data: D, | |||
| entities: Ref<'a, Entities>, | |||
| phantom: PhantomData<T>, | |||
| } | |||
| pub struct AntiStorage<'a>(pub &'a BitSet); | |||
| impl<'a, T, D> StorageWrapper<'a, T, D> { | |||
| pub fn new(data: D, entities: Ref<'a, Entities>) -> Self { | |||
| Self { | |||
| @@ -37,4 +44,71 @@ where | |||
| 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) {} | |||
| } | |||