Skip to content

Commit

Permalink
implement subset locking
Browse files Browse the repository at this point in the history
This has required some substantial changes to the lifetimes on the pipeline and for_each implementations. Unfortunately, my abuses of the type system have unearthed a compiler bug in the form of rust-lang/rust#33364, which is currently blocking users from calling Query::for_each with a closure that destructures the data tuple in the arguments list. Instead, they have to destructure it with a "let" binding within the closure body. This is less ergonomic but acceptable.
  • Loading branch information
rphmeier committed May 3, 2016
1 parent 4164807 commit 0571fbe
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 25 deletions.
10 changes: 7 additions & 3 deletions src/ecs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use std::collections::VecDeque;
use std::marker::PhantomData;
use std::ops::Deref;

use self::set::*;
use self::query::*;

const ID_BITS: usize = 24;
Expand All @@ -13,6 +12,8 @@ const MIN_UNUSED: usize = 1024;
pub mod query;
pub mod set;

pub use self::set::Set;

/// A component is a piece of raw data which is associated with an entity.
///
/// "Systems" will typically iterate over all entities with a specific set of components,
Expand Down Expand Up @@ -297,7 +298,7 @@ impl<'a, S: 'a + Set> WorldHandle<'a, S> {
///
/// # Examples
/// ```
/// use snorkium::ecs::*;
/// # use snorkium::ecs::*;
/// #[derive(Clone, Copy)]
/// struct Position(f32, f32);
/// #[derive(Clone, Copy)]
Expand All @@ -310,7 +311,10 @@ impl<'a, S: 'a + Set> WorldHandle<'a, S> {
/// impl System for DotSystem {
/// // draw a dot for each entity with a position and the zero-sized dot component.
/// fn process<'a, S: 'a + Set>(&mut self, wh: WorldHandle<'a, S>) {
/// wh.query::<(Position, Dot)>().for_each(|e, (p, d)| {
/// // when https://github.com/rust-lang/rust/issues/33364 is fixed,
/// // you'll be able to match on the tuple inside the closure arguments list.
/// wh.query::<(Position, Dot)>().for_each(|e, item| {
/// let (p, _) = item;
/// draw_dot(p);
/// });
/// }
Expand Down
45 changes: 23 additions & 22 deletions src/ecs/query.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::marker::PhantomData;

use super::*;
use super::set::{Set, LockedSubset};
use super::set::{LockGroup, LockedSubset};

/// Filters are used to test properties of entities' data.
///
Expand Down Expand Up @@ -40,13 +40,14 @@ impl<T: Component> Filter for Has<T> {
/// and `Push`.
pub trait Pipeline<'a>: Sized {
type Item: 'a;
type LockGroup: for<'b> LockGroup<'b>;

/// Consume self along with handles to ECS state to pass all entities
/// fulfilling the pipeline's predicates to the functions along with
/// relevant component data. This will output a vector of the returned
/// outputs from the function.
fn for_each<F, U: Send, S: LockedSubset>(self, &S, &EntityManager, F) -> Vec<U>
where F: Sync + for <'b> Fn(VerifiedEntity, <Self as Pipeline<'b>>::Item) -> U;
fn for_each<F, U: Send, S: LockedSubset>(self, &'a S, &'a EntityManager, F) -> Vec<U>
where F: Sync + Fn(VerifiedEntity, Self::Item) -> U;
}

/// Convenience trait for extending tuples of filters.
Expand Down Expand Up @@ -75,7 +76,7 @@ pub struct Query<'a, S: Set + 'a, P: 'a> {
pipeline: P,
}

impl<'a, S: 'a + Set, P: 'a + Pipeline<'a>> Query<'a, S, P> {
impl<'a, S: 'a + Set, P> Query<'a, S, P> where P: 'a + for<'b> Pipeline<'b> {
/// Create a new query. Use of `WorldHandle::query()` is advised
/// over this.
pub fn new(s: &'a S, entities: &'a EntityManager, pipeline: P) -> Self {
Expand Down Expand Up @@ -113,11 +114,9 @@ impl<'a, S: 'a + Set, P: 'a + Pipeline<'a>> Query<'a, S, P> {
/// Perform an action for each entity which fits the properties of
/// the filter.
pub fn for_each<F, U: Send>(self, f: F) -> Vec<U>
where F: Sync + for<'b> Fn(VerifiedEntity, <P as Pipeline<'b>>::Item) -> U {
// TODO: amend Pipeline so that we can get a LockGroup to pass to lock_subset.
// TODO: have for_each return the locked subset along with the items.
let empty = ::ecs::set::Empty;
self.pipeline.for_each(&empty, self.entities, f)
where F: Sync + for<'r> Fn(VerifiedEntity, <P as Pipeline<'r>>::Item) -> U {
let subset = self.set.lock_subset::<P::LockGroup>();
self.pipeline.for_each(&subset, self.entities, f)
}
}

Expand Down Expand Up @@ -163,10 +162,10 @@ macro_rules! factory {
};
}

// factory!(A B C D E F);
// factory!(A B C D E);
// factory!(A B C D);
// factory!(A B C);
factory!(A B C D E F);
factory!(A B C D E);
factory!(A B C D);
factory!(A B C);
factory!(A B);
factory!(A);
factory!();
Expand Down Expand Up @@ -208,9 +207,10 @@ macro_rules! pipeline_impl {
() => {
impl<'a> Pipeline<'a> for () {
type Item = ();
type LockGroup = ();

fn for_each<F, U: Send, S: LockedSubset>(self, _: &S, _: &EntityManager, _: F) -> Vec<U>
where F: 'a + Sync + for<'b> Fn(VerifiedEntity, <Self as Pipeline<'b>>::Item) -> U {
fn for_each<F, U: Send, S: LockedSubset>(self, _: &'a S, _: &'a EntityManager, _: F) -> Vec<U>
where F: 'a + Sync + Fn(VerifiedEntity, Self::Item) -> U {
Vec::new()
}
}
Expand All @@ -219,11 +219,12 @@ macro_rules! pipeline_impl {
($f_id: ident $f_num: tt $($id: ident $num: tt)*) => {
impl<'a, $f_id: Filter, $($id: Filter,)*> Pipeline<'a> for
($f_id, $($id,)*) {
type Item = (&'a <$f_id as Filter>::Component, $(&'a <$id as Filter>::Component,)*);
type Item = (&'a $f_id::Component, $(&'a $id::Component,)*);
type LockGroup = ($f_id::Component, $($id::Component,)*);

#[allow(unused_mut)]
fn for_each<OP, U: Send, SET: LockedSubset>(self, set: &SET, entities: &EntityManager, f: OP) -> Vec<U>
where OP: 'a + Sync + for<'b> Fn(VerifiedEntity, <Self as Pipeline<'b>>::Item) -> U {
fn for_each<OP, U: Send, SET: LockedSubset>(self, set: &'a SET, entities: &'a EntityManager, f: OP) -> Vec<U>
where OP: 'a + Sync + Fn(VerifiedEntity, Self::Item) -> U {
// it's ok to unwrap the calls to get_storage() since this function is called with a subset
// that has been locked with this pipeline in mind.

Expand Down Expand Up @@ -253,10 +254,10 @@ macro_rules! pipeline_impl {
};
}

// pipeline_impl!(A 0 B 1 C 2 D 3 E 4 F 5);
// pipeline_impl!(A 0 B 1 C 2 D 3 E 4);
// pipeline_impl!(A 0 B 1 C 2 D 3);
// pipeline_impl!(A 0 B 1 C 2);
pipeline_impl!(A 0 B 1 C 2 D 3 E 4 F 5);
pipeline_impl!(A 0 B 1 C 2 D 3 E 4);
pipeline_impl!(A 0 B 1 C 2 D 3);
pipeline_impl!(A 0 B 1 C 2);
pipeline_impl!(A 0 B 1);
pipeline_impl!(A 0);
pipeline_impl!();

0 comments on commit 0571fbe

Please sign in to comment.