Skip to content

Commit

Permalink
Add a method iter_combinations on query to iterate over combination…
Browse files Browse the repository at this point in the history
…s of query results (#1763)

Related to [discussion on discord](https://discord.com/channels/691052431525675048/742569353878437978/824731187724681289)

With const generics, it is now possible to write generic iterator over multiple entities at once.

This enables patterns of query iterations like

```rust
for [e1, e2, e3] in query.iter_combinations() {
   // do something with relation of all three entities
}
```

The compiler is able to infer the correct iterator for given size of array, so either of those work
```rust
for [e1, e2] in query.iter_combinations()  { ... }
for [e1, e2, e3] in query.iter_combinations()  { ... }
```

This feature can be very useful for systems like collision detection.

When you ask for permutations of size K of N entities:
- if K == N, you get one result of all entities
- if K < N, you get all possible subsets of N with size K, without repetition
- if K > N, the result set is empty (no permutation of size K exist)

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
  • Loading branch information
Frizi and cart committed May 17, 2021
1 parent cb98d31 commit a81fb7a
Show file tree
Hide file tree
Showing 7 changed files with 799 additions and 9 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,10 @@ path = "examples/ecs/fixed_timestep.rs"
name = "hierarchy"
path = "examples/ecs/hierarchy.rs"

[[example]]
name = "iter_combinations"
path = "examples/ecs/iter_combinations.rs"

[[example]]
name = "parallel_query"
path = "examples/ecs/parallel_query.rs"
Expand Down
27 changes: 27 additions & 0 deletions crates/bevy_ecs/src/query/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,18 @@ pub struct ReadFetch<T> {
sparse_set: *const ComponentSparseSet,
}

impl<T> Clone for ReadFetch<T> {
fn clone(&self) -> Self {
Self {
storage_type: self.storage_type,
table_components: self.table_components,
entity_table_rows: self.entity_table_rows,
entities: self.entities,
sparse_set: self.sparse_set,
}
}
}

/// SAFETY: access is read only
unsafe impl<T> ReadOnlyFetch for ReadFetch<T> {}

Expand Down Expand Up @@ -382,6 +394,21 @@ pub struct WriteFetch<T> {
change_tick: u32,
}

impl<T> Clone for WriteFetch<T> {
fn clone(&self) -> Self {
Self {
storage_type: self.storage_type,
table_components: self.table_components,
table_ticks: self.table_ticks,
entities: self.entities,
entity_table_rows: self.entity_table_rows,
sparse_set: self.sparse_set,
last_change_tick: self.last_change_tick,
change_tick: self.change_tick,
}
}
}

/// The [`FetchState`] of `&mut T`.
pub struct WriteState<T> {
component_id: ComponentId,
Expand Down
Loading

0 comments on commit a81fb7a

Please sign in to comment.