Skip to content

Commit 759d12a

Browse files
committed
Implement QueryBorrowChecked As Generic Over Fetch
This should help us implement a `DynamicQuery`.
1 parent 6c30bf2 commit 759d12a

File tree

2 files changed

+96
-55
lines changed

2 files changed

+96
-55
lines changed

crates/bevy_ecs/hecs/src/query.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use crate::{archetype::Archetype, Component, Entity, MissingComponent};
2525
/// A collection of component types to fetch from a `World`
2626
pub trait Query {
2727
#[doc(hidden)]
28-
type Fetch: for<'a> Fetch<'a>;
28+
type Fetch: for<'a> Fetch<'a, State=()>;
2929
}
3030

3131
/// A fetch that is read only. This should only be implemented for read-only fetches.

crates/bevy_ecs/src/system/query.rs

Lines changed: 95 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use std::marker::PhantomData;
1111
pub struct Query<'a, Q: HecsQuery> {
1212
pub(crate) world: &'a World,
1313
pub(crate) archetype_access: &'a ArchetypeAccess,
14+
state: &'static (),
1415
_marker: PhantomData<Q>,
1516
}
1617

@@ -23,19 +24,23 @@ pub enum QueryError {
2324
NoSuchEntity,
2425
}
2526

26-
impl<'a, Q: HecsQuery> Query<'a, Q> {
27+
impl<'w, Q: HecsQuery> Query<'w, Q>
28+
where
29+
Q::Fetch: for<'a> Fetch<'a, State = ()>,
30+
{
2731
#[inline]
28-
pub fn new(world: &'a World, archetype_access: &'a ArchetypeAccess) -> Self {
32+
pub fn new(world: &'w World, archetype_access: &'w ArchetypeAccess) -> Self {
2933
Self {
3034
world,
3135
archetype_access,
36+
state: &(),
3237
_marker: PhantomData::default(),
3338
}
3439
}
3540

3641
#[inline]
37-
pub fn iter(&mut self) -> QueryBorrowChecked<'_, Q> {
38-
QueryBorrowChecked::new(&self.world.archetypes, self.archetype_access)
42+
pub fn iter(&mut self) -> QueryBorrowChecked<'w, 'static, (), Q::Fetch> {
43+
QueryBorrowChecked::new(&self.world.archetypes, self.archetype_access, &self.state)
3944
}
4045

4146
// TODO: find a way to make `iter`, `get`, `get_mut`, and `entity` safe without using tracking pointers with global locks
@@ -133,19 +138,27 @@ impl<'a, Q: HecsQuery> Query<'a, Q> {
133138
/// A borrow of a `World` sufficient to execute the query `Q`
134139
///
135140
/// Note that borrows are not released until this object is dropped.
136-
pub struct QueryBorrowChecked<'w, Q: HecsQuery> {
141+
pub struct QueryBorrowChecked<'w, 's, S: Default + Sync + Send, F: for<'a> Fetch<'a, State = S>> {
137142
archetypes: &'w [Archetype],
138143
archetype_access: &'w ArchetypeAccess,
144+
state: &'s S,
139145
borrowed: bool,
140-
_marker: PhantomData<Q>,
146+
_marker: PhantomData<F>,
141147
}
142148

143-
impl<'w, Q: HecsQuery> QueryBorrowChecked<'w, Q> {
144-
pub(crate) fn new(archetypes: &'w [Archetype], archetype_access: &'w ArchetypeAccess) -> Self {
149+
impl<'w, 's, S: Default + Sync + Send, F: for<'a> Fetch<'a, State = S>>
150+
QueryBorrowChecked<'w, 's, S, F>
151+
{
152+
pub(crate) fn new(
153+
archetypes: &'w [Archetype],
154+
archetype_access: &'w ArchetypeAccess,
155+
state: &'s S,
156+
) -> Self {
145157
Self {
146158
archetypes,
147159
borrowed: false,
148160
archetype_access,
161+
state,
149162
_marker: PhantomData,
150163
}
151164
}
@@ -154,7 +167,7 @@ impl<'w, Q: HecsQuery> QueryBorrowChecked<'w, Q> {
154167
///
155168
/// Must be called only once per query.
156169
#[inline]
157-
pub fn iter<'q>(&'q mut self) -> QueryIter<'q, 'w, Q> {
170+
pub fn iter<'q>(&'q mut self) -> QueryIter<'q, 'w, 's, S, F> {
158171
self.borrow();
159172
QueryIter {
160173
borrow: self,
@@ -177,7 +190,7 @@ impl<'w, Q: HecsQuery> QueryBorrowChecked<'w, Q> {
177190
/// each batch could take longer than running the batch. On the other
178191
/// hand, a too large batch size risks that one batch is still running
179192
/// long after the rest have finished.
180-
pub fn par_iter<'q>(&'q mut self, batch_size: usize) -> ParIter<'q, 'w, Q> {
193+
pub fn par_iter<'q>(&'q mut self, batch_size: usize) -> ParIter<'q, 'w, 's, S, F> {
181194
self.borrow();
182195
ParIter {
183196
borrow: self,
@@ -195,38 +208,50 @@ impl<'w, Q: HecsQuery> QueryBorrowChecked<'w, Q> {
195208
}
196209

197210
for index in self.archetype_access.immutable.ones() {
198-
Q::Fetch::borrow(&self.archetypes[index], &Default::default());
211+
F::borrow(&self.archetypes[index], self.state);
199212
}
200213

201214
for index in self.archetype_access.mutable.ones() {
202-
Q::Fetch::borrow(&self.archetypes[index], &Default::default());
215+
F::borrow(&self.archetypes[index], self.state);
203216
}
204217

205218
self.borrowed = true;
206219
}
207220
}
208221

209-
unsafe impl<'w, Q: HecsQuery> Send for QueryBorrowChecked<'w, Q> {}
210-
unsafe impl<'w, Q: HecsQuery> Sync for QueryBorrowChecked<'w, Q> {}
222+
unsafe impl<'w, 's, S: Default + Sync + Send, F: for<'a> Fetch<'a, State = S>> Send
223+
for QueryBorrowChecked<'w, 's, S, F>
224+
{
225+
}
226+
unsafe impl<'w, 's, S: Default + Sync + Send, F: for<'a> Fetch<'a, State = S>> Sync
227+
for QueryBorrowChecked<'w, 's, S, F>
228+
{
229+
}
211230

212-
impl<'w, Q: HecsQuery> Drop for QueryBorrowChecked<'w, Q> {
231+
impl<'w, 's, S: Default + Sync + Send, F: for<'a> Fetch<'a, State = S>> Drop
232+
for QueryBorrowChecked<'w, 's, S, F>
233+
{
213234
#[inline]
214235
fn drop(&mut self) {
215236
if self.borrowed {
216237
for index in self.archetype_access.immutable.ones() {
217-
Q::Fetch::release(&self.archetypes[index], &Default::default());
238+
F::release(&self.archetypes[index], self.state);
218239
}
219240

220241
for index in self.archetype_access.mutable.ones() {
221-
Q::Fetch::release(&self.archetypes[index], &Default::default());
242+
F::release(&self.archetypes[index], self.state);
222243
}
223244
}
224245
}
225246
}
226247

227-
impl<'q, 'w, Q: HecsQuery> IntoIterator for &'q mut QueryBorrowChecked<'w, Q> {
228-
type IntoIter = QueryIter<'q, 'w, Q>;
229-
type Item = <Q::Fetch as Fetch<'q>>::Item;
248+
impl<'q, 'w, 's, S: Default + Sync + Send, F: for<'a> Fetch<'a, State = S>> IntoIterator
249+
for &'q mut QueryBorrowChecked<'w, 's, S, F>
250+
{
251+
type IntoIter = QueryIter<'q, 'w, 's, S, F>;
252+
// FIXME: do I specify the concrete 'w? I tried to kind of avoid that a little with the `for<'a>
253+
// Fetch<'a>` trait bound.
254+
type Item = <F as Fetch<'q>>::Item;
230255

231256
#[inline]
232257
fn into_iter(self) -> Self::IntoIter {
@@ -235,17 +260,25 @@ impl<'q, 'w, Q: HecsQuery> IntoIterator for &'q mut QueryBorrowChecked<'w, Q> {
235260
}
236261

237262
/// Iterator over the set of entities with the components in `Q`
238-
pub struct QueryIter<'q, 'w, Q: HecsQuery> {
239-
borrow: &'q mut QueryBorrowChecked<'w, Q>,
263+
pub struct QueryIter<'q, 'w, 's, S: Default + Sync + Send, F: for<'a> Fetch<'a, State = S>> {
264+
borrow: &'q mut QueryBorrowChecked<'w, 's, S, F>,
240265
archetype_index: usize,
241-
iter: Option<ChunkIter<Q>>,
266+
iter: Option<ChunkIter<'s, S, F>>,
242267
}
243268

244-
unsafe impl<'q, 'w, Q: HecsQuery> Send for QueryIter<'q, 'w, Q> {}
245-
unsafe impl<'q, 'w, Q: HecsQuery> Sync for QueryIter<'q, 'w, Q> {}
269+
unsafe impl<'q, 'w, 's, S: Default + Sync + Send, F: for<'a> Fetch<'a, State = S>> Send
270+
for QueryIter<'q, 'w, 's, S, F>
271+
{
272+
}
273+
unsafe impl<'q, 'w, 's, S: Default + Sync + Send, F: for<'a> Fetch<'a, State = S>> Sync
274+
for QueryIter<'q, 'w, 's, S, F>
275+
{
276+
}
246277

247-
impl<'q, 'w, Q: HecsQuery> Iterator for QueryIter<'q, 'w, Q> {
248-
type Item = <Q::Fetch as Fetch<'q>>::Item;
278+
impl<'q, 'w, 's, S: Default + Sync + Send, F: for<'a> Fetch<'a, State = S>> Iterator
279+
for QueryIter<'q, 'w, 's, S, F>
280+
{
281+
type Item = <F as Fetch<'q>>::Item;
249282

250283
#[inline]
251284
fn next(&mut self) -> Option<Self::Item> {
@@ -255,11 +288,10 @@ impl<'q, 'w, Q: HecsQuery> Iterator for QueryIter<'q, 'w, Q> {
255288
let archetype = self.borrow.archetypes.get(self.archetype_index as usize)?;
256289
self.archetype_index += 1;
257290
unsafe {
258-
self.iter = Q::Fetch::get(archetype, 0, &Default::default()).map(|fetch| {
259-
ChunkIter {
260-
fetch,
261-
len: archetype.len(),
262-
}
291+
self.iter = F::get(archetype, 0, self.borrow.state).map(|fetch| ChunkIter {
292+
fetch,
293+
len: archetype.len(),
294+
state: self.borrow.state,
263295
});
264296
}
265297
}
@@ -282,54 +314,59 @@ impl<'q, 'w, Q: HecsQuery> Iterator for QueryIter<'q, 'w, Q> {
282314
}
283315
}
284316

285-
impl<'q, 'w, Q: HecsQuery> ExactSizeIterator for QueryIter<'q, 'w, Q> {
317+
impl<'q, 'w, 's, S: Default + Sync + Send, F: for<'a> Fetch<'a, State = S>> ExactSizeIterator
318+
for QueryIter<'q, 'w, 's, S, F>
319+
{
286320
fn len(&self) -> usize {
287321
self.borrow
288322
.archetypes
289323
.iter()
290-
.filter(|&x| Q::Fetch::access(x, &Default::default()).is_some())
324+
.filter(|&x| F::access(x, self.borrow.state).is_some())
291325
.map(|x| x.len())
292326
.sum()
293327
}
294328
}
295329

296-
struct ChunkIter<Q: HecsQuery> {
297-
fetch: Q::Fetch,
330+
struct ChunkIter<'s, S: Default + Sync + Send, F: for<'a> Fetch<'a, State = S>> {
331+
fetch: F,
298332
len: usize,
333+
state: &'s S,
299334
}
300335

301-
impl<Q: HecsQuery> ChunkIter<Q> {
336+
impl<'s, S: Default + Sync + Send, F: for<'a> Fetch<'a, State = S>> ChunkIter<'s, S, F> {
302337
#[inline]
303-
unsafe fn next<'a>(&mut self) -> Option<<Q::Fetch as Fetch<'a>>::Item> {
338+
unsafe fn next<'a>(&mut self) -> Option<<F as Fetch<'a>>::Item> {
304339
loop {
305340
if self.len == 0 {
306341
return None;
307342
}
308343

309344
self.len -= 1;
310-
if self.fetch.should_skip(&Default::default()) {
345+
if self.fetch.should_skip(self.state) {
311346
// we still need to progress the iterator
312-
let _ = self.fetch.next(&Default::default());
347+
let _ = self.fetch.next(self.state);
313348
continue;
314349
}
315350

316-
break Some(self.fetch.next(&Default::default()));
351+
break Some(self.fetch.next(self.state));
317352
}
318353
}
319354
}
320355

321356
/// Batched version of `QueryIter`
322-
pub struct ParIter<'q, 'w, Q: HecsQuery> {
323-
borrow: &'q mut QueryBorrowChecked<'w, Q>,
357+
pub struct ParIter<'q, 'w, 's, S: Default + Sync + Send, F: for<'a> Fetch<'a, State = S>> {
358+
borrow: &'q mut QueryBorrowChecked<'w, 's, S, F>,
324359
archetype_index: usize,
325360
batch_size: usize,
326361
batch: usize,
327362
}
328363

329-
impl<'q, 'w, Q: HecsQuery> ParallelIterator<Batch<'q, Q>> for ParIter<'q, 'w, Q> {
330-
type Item = <Q::Fetch as Fetch<'q>>::Item;
364+
impl<'q, 'w, 's, S: Default + Sync + Send, F: for<'a> Fetch<'a, State = S>>
365+
ParallelIterator<Batch<'q, 's, S, F>> for ParIter<'q, 'w, 's, S, F>
366+
{
367+
type Item = <F as Fetch<'q>>::Item;
331368

332-
fn next_batch(&mut self) -> Option<Batch<'q, Q>> {
369+
fn next_batch(&mut self) -> Option<Batch<'q, 's, S, F>> {
333370
loop {
334371
let archetype = self.borrow.archetypes.get(self.archetype_index)?;
335372
let offset = self.batch_size * self.batch;
@@ -338,15 +375,14 @@ impl<'q, 'w, Q: HecsQuery> ParallelIterator<Batch<'q, Q>> for ParIter<'q, 'w, Q>
338375
self.batch = 0;
339376
continue;
340377
}
341-
if let Some(fetch) =
342-
unsafe { Q::Fetch::get(archetype, offset as usize, &Default::default()) }
343-
{
378+
if let Some(fetch) = unsafe { F::get(archetype, offset as usize, self.borrow.state) } {
344379
self.batch += 1;
345380
return Some(Batch {
346381
_marker: PhantomData,
347382
state: ChunkIter {
348383
fetch,
349384
len: self.batch_size.min(archetype.len() - offset),
385+
state: self.borrow.state,
350386
},
351387
});
352388
} else {
@@ -362,21 +398,26 @@ impl<'q, 'w, Q: HecsQuery> ParallelIterator<Batch<'q, Q>> for ParIter<'q, 'w, Q>
362398
}
363399

364400
/// A sequence of entities yielded by `ParIter`
365-
pub struct Batch<'q, Q: HecsQuery> {
401+
pub struct Batch<'q, 's, S: Default + Sync + Send, F: for<'a> Fetch<'a, State = S>> {
366402
_marker: PhantomData<&'q ()>,
367-
state: ChunkIter<Q>,
403+
state: ChunkIter<'s, S, F>,
368404
}
369405

370-
impl<'q, 'w, Q: HecsQuery> Iterator for Batch<'q, Q> {
371-
type Item = <Q::Fetch as Fetch<'q>>::Item;
406+
impl<'q, 'w, 's, S: Default + Sync + Send, F: for<'a> Fetch<'a, State = S>> Iterator
407+
for Batch<'q, 's, S, F>
408+
{
409+
type Item = <F as Fetch<'q>>::Item;
372410

373411
fn next(&mut self) -> Option<Self::Item> {
374412
let components = unsafe { self.state.next()? };
375413
Some(components)
376414
}
377415
}
378416

379-
unsafe impl<'q, Q: HecsQuery> Send for Batch<'q, Q> {}
417+
unsafe impl<'q, 's, S: Default + Sync + Send, F: for<'a> Fetch<'a, State = S>> Send
418+
for Batch<'q, 's, S, F>
419+
{
420+
}
380421

381422
/// A borrow of a `World` sufficient to execute the query `Q` on a single entity
382423
pub struct QueryOneChecked<'a, Q: HecsQuery> {

0 commit comments

Comments
 (0)