specs/join/mod.rs
1//! Joining of components for iteration over entities with specific components.
2
3use hibitset::{BitIter, BitSetLike};
4use shred::{Fetch, FetchMut, Read, ReadExpect, Resource, Write, WriteExpect};
5use std::ops::{Deref, DerefMut};
6
7use crate::world::Index;
8
9mod bit_and;
10mod lend_join;
11mod maybe;
12#[cfg(feature = "parallel")]
13mod par_join;
14
15pub use bit_and::BitAnd;
16#[nougat::gat(Type)]
17pub use lend_join::LendJoin;
18pub use lend_join::{JoinLendIter, LendJoinType, RepeatableLendGet};
19pub use maybe::MaybeJoin;
20#[cfg(feature = "parallel")]
21pub use par_join::{JoinParIter, ParJoin};
22
23/// The purpose of the `Join` trait is to provide a way
24/// to access multiple storages at the same time with
25/// the merged bit set.
26///
27/// Joining component storages means that you'll only get values where
28/// for a given entity every storage has an associated component.
29///
30/// ## Example
31///
32/// ```
33/// # use specs::prelude::*;
34/// # use specs::world::EntitiesRes;
35/// # #[derive(Debug, PartialEq)]
36/// # struct Pos; impl Component for Pos { type Storage = VecStorage<Self>; }
37/// # #[derive(Debug, PartialEq)]
38/// # struct Vel; impl Component for Vel { type Storage = VecStorage<Self>; }
39/// let mut world = World::new();
40///
41/// world.register::<Pos>();
42/// world.register::<Vel>();
43///
44/// {
45/// let pos = world.read_storage::<Pos>();
46/// let vel = world.read_storage::<Vel>();
47///
48/// // There are no entities yet, so no pair will be returned.
49/// let joined: Vec<_> = (&pos, &vel).join().collect();
50/// assert_eq!(joined, vec![]);
51/// }
52///
53/// world.create_entity().with(Pos).build();
54///
55/// {
56/// let pos = world.read_storage::<Pos>();
57/// let vel = world.read_storage::<Vel>();
58///
59/// // Although there is an entity, it only has `Pos`.
60/// let joined: Vec<_> = (&pos, &vel).join().collect();
61/// assert_eq!(joined, vec![]);
62/// }
63///
64/// let ent = world.create_entity().with(Pos).with(Vel).build();
65///
66/// {
67/// let pos = world.read_storage::<Pos>();
68/// let vel = world.read_storage::<Vel>();
69///
70/// // Now there is one entity that has both a `Vel` and a `Pos`.
71/// let joined: Vec<_> = (&pos, &vel).join().collect();
72/// assert_eq!(joined, vec![(&Pos, &Vel)]);
73///
74/// // If we want to get the entity the components are associated to,
75/// // we need to join over `Entities`:
76///
77/// let entities = world.read_resource::<EntitiesRes>();
78/// // note: `EntitiesRes` is the fetched resource; we get back
79/// // `Read<EntitiesRes>`.
80/// // `Read<EntitiesRes>` can also be referred to by `Entities` which
81/// // is a shorthand type definition to the former type.
82///
83/// let joined: Vec<_> = (&entities, &pos, &vel).join().collect();
84/// assert_eq!(joined, vec![(ent, &Pos, &Vel)]);
85/// }
86/// ```
87///
88/// ## Iterating over a single storage
89///
90/// `Join` can also be used to iterate over a single
91/// storage, just by writing `(&storage).join()`.
92///
93/// # Safety
94///
95/// The `Self::Mask` value returned with the `Self::Value` must correspond such
96/// that it is safe to retrieve items from `Self::Value` whose presence is
97/// indicated in the mask. As part of this, `BitSetLike::iter` must not produce
98/// an iterator that repeats an `Index` value.
99pub unsafe trait Join {
100 /// Type of joined components.
101 type Type;
102 /// Type of joined storages.
103 type Value;
104 /// Type of joined bit mask.
105 type Mask: BitSetLike;
106
107 /// Create a joined iterator over the contents.
108 fn join(self) -> JoinIter<Self>
109 where
110 Self: Sized,
111 {
112 JoinIter::new(self)
113 }
114
115 /// Open this join by returning the mask and the storages.
116 ///
117 /// # Safety
118 ///
119 /// This is unsafe because implementations of this trait can permit the
120 /// `Value` to be mutated independently of the `Mask`. If the `Mask` does
121 /// not correctly report the status of the `Value` then illegal memory
122 /// access can occur.
123 unsafe fn open(self) -> (Self::Mask, Self::Value);
124
125 /// Get a joined component value by a given index.
126 ///
127 ///
128 /// # Safety
129 ///
130 /// * A call to `get` must be preceded by a check if `id` is part of
131 /// `Self::Mask`.
132 /// * Multiple calls with the same `id` are not allowed, for a particular
133 /// instance of the values from [`open`](Join::open).
134 unsafe fn get(value: &mut Self::Value, id: Index) -> Self::Type;
135
136 /// If this `Join` typically returns all indices in the mask, then iterating
137 /// over only it or combined with other joins that are also dangerous will
138 /// cause the `JoinIter` to go through all indices which is usually not what
139 /// is wanted and will kill performance.
140 #[inline]
141 fn is_unconstrained() -> bool {
142 false
143 }
144}
145
146/// `JoinIter` is an `Iterator` over a group of storages.
147#[must_use]
148pub struct JoinIter<J: Join> {
149 keys: BitIter<J::Mask>,
150 values: J::Value,
151}
152
153impl<J: Join> JoinIter<J> {
154 /// Create a new join iterator.
155 pub fn new(j: J) -> Self {
156 if <J as Join>::is_unconstrained() {
157 log::warn!(
158 "`Join` possibly iterating through all indices, \
159 you might've made a join with all `MaybeJoin`s, \
160 which is unbounded in length."
161 );
162 }
163
164 // SAFETY: We do not swap out the mask or the values, nor do we allow it
165 // by exposing them.
166 let (keys, values) = unsafe { j.open() };
167 JoinIter {
168 keys: keys.iter(),
169 values,
170 }
171 }
172}
173
174impl<J: Join> std::iter::Iterator for JoinIter<J> {
175 type Item = J::Type;
176
177 fn next(&mut self) -> Option<J::Type> {
178 // SAFETY: Since `idx` is yielded from `keys` (the mask), it is
179 // necessarily a part of it. `Join` requires that the iterator doesn't
180 // repeat indices and we advance the iterator for each `get` call.
181 self.keys
182 .next()
183 .map(|idx| unsafe { J::get(&mut self.values, idx) })
184 }
185}
186
187// Implementations of `LendJoin`, `Join`, and `ParJoin` for tuples, `Fetch`,
188// `Read`, `ReadExpect`, `FetchMut`, `Write`, and `WriteExpect`.
189
190macro_rules! define_open {
191 // use variables to indicate the arity of the tuple
192 ($($from:ident),*) => {
193 // SAFETY: The returned mask in `open` is the intersection of the masks
194 // from each type in this tuple. So if an `id` is present in the
195 // combined mask, it will be safe to retrieve the corresponding items.
196 // Iterating the mask does not repeat indices.
197 #[nougat::gat]
198 unsafe impl<$($from,)*> LendJoin for ($($from),*,)
199 where $($from: LendJoin),*,
200 ($(<$from as LendJoin>::Mask,)*): BitAnd,
201 {
202 type Type<'next> = ($(<$from as LendJoin>::Type<'next>),*,);
203 type Value = ($($from::Value),*,);
204 type Mask = <($($from::Mask,)*) as BitAnd>::Value;
205
206 #[allow(non_snake_case)]
207 unsafe fn open(self) -> (Self::Mask, Self::Value) {
208 let ($($from,)*) = self;
209 // SAFETY: While we do expose the mask and the values and
210 // therefore would allow swapping them, this method is `unsafe`
211 // and relies on the same invariants.
212 let ($($from,)*) = unsafe { ($($from.open(),)*) };
213 (
214 ($($from.0),*,).and(),
215 ($($from.1),*,)
216 )
217 }
218
219 #[allow(non_snake_case)]
220 unsafe fn get<'next>(v: &'next mut Self::Value, i: Index) -> Self::Type<'next>
221
222 {
223 let &mut ($(ref mut $from,)*) = v;
224 // SAFETY: `get` is safe to call as the caller must have checked
225 // the mask, which only has a key that exists in all of the
226 // storages. Requirement to not call with the same ID more than
227 // once (unless `RepeatableLendGet` is implemented) is passed to
228 // the caller.
229 unsafe { ($($from::get($from, i),)*) }
230 }
231
232 #[inline]
233 fn is_unconstrained() -> bool {
234 let mut unconstrained = true;
235 $( unconstrained = unconstrained && $from::is_unconstrained(); )*
236 unconstrained
237 }
238 }
239
240 // SAFETY: Tuple impls of `LendJoin` simply defer to the individual
241 // storages. Thus, if all of them implement this, it is safe to call
242 // `LendJoin::get` multiple times with the same ID.
243 unsafe impl<$($from,)*> RepeatableLendGet for ($($from),*,)
244 where $($from: RepeatableLendGet),*,
245 ($(<$from as LendJoin>::Mask,)*): BitAnd, {}
246
247 // SAFETY: The returned mask in `open` is the intersection of the masks
248 // from each type in this tuple. So if an `id` is present in the
249 // combined mask, it will be safe to retrieve the corresponding items.
250 // Iterating the mask does not repeat indices.
251 unsafe impl<$($from,)*> Join for ($($from),*,)
252 where $($from: Join),*,
253 ($(<$from as Join>::Mask,)*): BitAnd,
254 {
255 type Type = ($($from::Type),*,);
256 type Value = ($($from::Value),*,);
257 type Mask = <($($from::Mask,)*) as BitAnd>::Value;
258
259 #[allow(non_snake_case)]
260 unsafe fn open(self) -> (Self::Mask, Self::Value) {
261 let ($($from,)*) = self;
262 // SAFETY: While we do expose the mask and the values and
263 // therefore would allow swapping them, this method is `unsafe`
264 // and relies on the same invariants.
265 let ($($from,)*) = unsafe { ($($from.open(),)*) };
266 (
267 ($($from.0),*,).and(),
268 ($($from.1),*,)
269 )
270 }
271
272 #[allow(non_snake_case)]
273 unsafe fn get(v: &mut Self::Value, i: Index) -> Self::Type {
274 let &mut ($(ref mut $from,)*) = v;
275 // SAFETY: `get` is safe to call as the caller must have checked
276 // the mask, which only has a key that exists in all of the
277 // storages. Requirement to not use the same ID multiple times
278 // is also passed to the caller.
279 unsafe { ($($from::get($from, i),)*) }
280 }
281
282 #[inline]
283 fn is_unconstrained() -> bool {
284 let mut unconstrained = true;
285 $( unconstrained = unconstrained && $from::is_unconstrained(); )*
286 unconstrained
287 }
288 }
289
290 // SAFETY: This is safe to implement since all components implement
291 // `ParJoin`. If the access of every individual `get` is callable from
292 // multiple threads, then this `get` method will be as well.
293 //
294 // The returned mask in `open` is the intersection of the masks
295 // from each type in this tuple. So if an `id` is present in the
296 // combined mask, it will be safe to retrieve the corresponding items.
297 // Iterating the mask does not repeat indices.
298 #[cfg(feature = "parallel")]
299 unsafe impl<$($from,)*> ParJoin for ($($from),*,)
300 where $($from: ParJoin),*,
301 ($(<$from as ParJoin>::Mask,)*): BitAnd,
302 {
303 type Type = ($($from::Type),*,);
304 type Value = ($($from::Value),*,);
305 type Mask = <($($from::Mask,)*) as BitAnd>::Value;
306
307 #[allow(non_snake_case)]
308 unsafe fn open(self) -> (Self::Mask, Self::Value) {
309 let ($($from,)*) = self;
310 // SAFETY: While we do expose the mask and the values and
311 // therefore would allow swapping them, this method is `unsafe`
312 // and relies on the same invariants.
313 let ($($from,)*) = unsafe { ($($from.open(),)*) };
314 (
315 ($($from.0),*,).and(),
316 ($($from.1),*,)
317 )
318 }
319
320 #[allow(non_snake_case)]
321 unsafe fn get(v: &Self::Value, i: Index) -> Self::Type {
322 let &($(ref $from,)*) = v;
323 // SAFETY: `get` is safe to call as the caller must have checked
324 // the mask, which only has a key that exists in all of the
325 // storages. Requirement for the return value to no longer be
326 // alive before subsequent calls with the same `id` is passed to
327 // the caller.
328 unsafe { ($($from::get($from, i),)*) }
329 }
330
331 #[inline]
332 fn is_unconstrained() -> bool {
333 let mut unconstrained = true;
334 $( unconstrained = unconstrained && $from::is_unconstrained(); )*
335 unconstrained
336 }
337 }
338 }
339}
340
341define_open! {A}
342define_open! {A, B}
343define_open! {A, B, C}
344define_open! {A, B, C, D}
345define_open! {A, B, C, D, E}
346define_open! {A, B, C, D, E, F}
347define_open! {A, B, C, D, E, F, G}
348define_open! {A, B, C, D, E, F, G, H}
349define_open! {A, B, C, D, E, F, G, H, I}
350define_open! {A, B, C, D, E, F, G, H, I, J}
351define_open! {A, B, C, D, E, F, G, H, I, J, K}
352define_open! {A, B, C, D, E, F, G, H, I, J, K, L}
353define_open! {A, B, C, D, E, F, G, H, I, J, K, L, M}
354define_open! {A, B, C, D, E, F, G, H, I, J, K, L, M, N}
355define_open! {A, B, C, D, E, F, G, H, I, J, K, L, M, N, O}
356define_open! {A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P}
357define_open!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q);
358define_open!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R);
359
360/// `Fetch`/`Read`/`Write`/etc. all implement `Deref`/`DerefMut` but Rust does
361/// not implicitly dereference the wrapper type when we are joining which
362/// creates annoying scenarios like `&*entities` where we have to reborrow the
363/// type unnecessarily.
364///
365/// So instead, we implement `Join` on the wrapper types and forward the
366/// implementations to the underlying types so that Rust doesn't have to do
367/// implicit magic to figure out what we want to do with the type.
368macro_rules! immutable_resource_join {
369 ($($ty:ty),*) => {
370 $(
371 // SAFETY: Since `T` implements `LendJoin` it is safe to deref and defer
372 // to its implementation.
373 #[nougat::gat]
374 unsafe impl<'a, 'b, T> LendJoin for &'a $ty
375 where
376 &'a T: LendJoin,
377 T: Resource,
378 {
379 type Type<'next> = <&'a T as LendJoin>::Type<'next>;
380 type Value = <&'a T as LendJoin>::Value;
381 type Mask = <&'a T as LendJoin>::Mask;
382
383 unsafe fn open(self) -> (Self::Mask, Self::Value) {
384 // SAFETY: This only wraps `T` and, while exposing the mask and
385 // the values, requires the same invariants as the original
386 // implementation and is thus safe.
387 unsafe { self.deref().open() }
388 }
389
390 unsafe fn get<'next>(v: &'next mut Self::Value, i: Index) -> Self::Type<'next>
391
392 {
393 // SAFETY: The mask of `Self` and `T` are identical, thus a
394 // check to `Self`'s mask (which is required) is equal to a
395 // check of `T`'s mask, which makes `get` safe to call.
396 // Requirement to not call with the same ID more than once
397 // (unless `RepeatableLendGet` is implemented) is passed to the
398 // caller.
399 unsafe { <&'a T as LendJoin>::get(v, i) }
400 }
401
402 #[inline]
403 fn is_unconstrained() -> bool {
404 <&'a T as LendJoin>::is_unconstrained()
405 }
406 }
407
408 // SAFETY: <&'a $ty as LendJoin>::get does not rely on only being called
409 // once with a particular ID as long as `&'a T` does not rely on this.
410 unsafe impl<'a, 'b, T> RepeatableLendGet for &'a $ty
411 where
412 &'a T: RepeatableLendGet,
413 T: Resource,
414 {}
415
416 // SAFETY: Since `T` implements `Join` it is safe to deref and defer to
417 // its implementation.
418 unsafe impl<'a, 'b, T> Join for &'a $ty
419 where
420 &'a T: Join,
421 T: Resource,
422 {
423 type Type = <&'a T as Join>::Type;
424 type Value = <&'a T as Join>::Value;
425 type Mask = <&'a T as Join>::Mask;
426
427 unsafe fn open(self) -> (Self::Mask, Self::Value) {
428 // SAFETY: This only wraps `T` and, while exposing the mask and
429 // the values, requires the same invariants as the original
430 // implementation and is thus safe.
431 unsafe { self.deref().open() }
432 }
433
434 unsafe fn get(v: &mut Self::Value, i: Index) -> Self::Type {
435 // SAFETY: The mask of `Self` and `T` are identical, thus a
436 // check to `Self`'s mask (which is required) is equal to a
437 // check of `T`'s mask, which makes `get` safe to call.
438 // Requirement to not use the same ID multiple times is passed
439 // to the caller.
440 unsafe { <&'a T as Join>::get(v, i) }
441 }
442
443 #[inline]
444 fn is_unconstrained() -> bool {
445 <&'a T as Join>::is_unconstrained()
446 }
447 }
448
449 // SAFETY: Since `T` implements `ParJoin` it is safe to deref and defer to
450 // its implementation. S-TODO we can rely on errors if $ty is not sync?
451 // Iterating the mask does not repeat indices.
452 #[cfg(feature = "parallel")]
453 unsafe impl<'a, 'b, T> ParJoin for &'a $ty
454 where
455 &'a T: ParJoin,
456 T: Resource,
457 {
458 type Type = <&'a T as ParJoin>::Type;
459 type Value = <&'a T as ParJoin>::Value;
460 type Mask = <&'a T as ParJoin>::Mask;
461
462 unsafe fn open(self) -> (Self::Mask, Self::Value) {
463 // SAFETY: This only wraps `T` and, while exposing the mask and
464 // the values, requires the same invariants as the original
465 // implementation and is thus safe.
466 unsafe { self.deref().open() }
467 }
468
469 unsafe fn get(v: &Self::Value, i: Index) -> Self::Type {
470 // SAFETY: The mask of `Self` and `T` are identical, thus a
471 // check to `Self`'s mask (which is required) is equal to a
472 // check of `T`'s mask, which makes `get` safe to call.
473 // Requirement for the return value to no longer be alive before
474 // subsequent calls with the same ID is passed to the caller.
475 unsafe { <&'a T as ParJoin>::get(v, i) }
476 }
477
478 #[inline]
479 fn is_unconstrained() -> bool {
480 <&'a T as ParJoin>::is_unconstrained()
481 }
482 }
483 )*
484 };
485}
486
487macro_rules! mutable_resource_join {
488 ($($ty:ty),*) => {
489 $(
490 // SAFETY: Since `T` implements `LendJoin` it is safe to deref and defer
491 // to its implementation.
492 #[nougat::gat]
493 unsafe impl<'a, 'b, T> LendJoin for &'a mut $ty
494 where
495 &'a mut T: LendJoin,
496 T: Resource,
497 {
498 type Type<'next> = <&'a mut T as LendJoin>::Type<'next>;
499 type Value = <&'a mut T as LendJoin>::Value;
500 type Mask = <&'a mut T as LendJoin>::Mask;
501
502 unsafe fn open(self) -> (Self::Mask, Self::Value) {
503 // SAFETY: This only wraps `T` and, while exposing the mask and
504 // the values, requires the same invariants as the original
505 // implementation and is thus safe.
506 unsafe { self.deref_mut().open() }
507 }
508
509 unsafe fn get<'next>(v: &'next mut Self::Value, i: Index) -> Self::Type<'next>
510
511 {
512 // SAFETY: The mask of `Self` and `T` are identical, thus a
513 // check to `Self`'s mask (which is required) is equal to a
514 // check of `T`'s mask, which makes `get_mut` safe to call.
515 // Requirement to not call with the same ID more than once
516 // (unless `RepeatableLendGet` is implemented) is passed to the
517 // caller.
518 unsafe { <&'a mut T as LendJoin>::get(v, i) }
519 }
520
521 #[inline]
522 fn is_unconstrained() -> bool {
523 <&'a mut T as LendJoin>::is_unconstrained()
524 }
525 }
526
527 // SAFETY: <&'a mut $ty as LendJoin>::get does not rely on only being
528 // called once with a particular ID as long as `&'a mut T` does not rely
529 // on this.
530 unsafe impl<'a, 'b, T> RepeatableLendGet for &'a mut $ty
531 where
532 &'a mut T: RepeatableLendGet,
533 T: Resource,
534 {}
535
536 // SAFETY: Since `T` implements `Join` it is safe to deref and defer to
537 // its implementation.
538 unsafe impl<'a, 'b, T> Join for &'a mut $ty
539 where
540 &'a mut T: Join,
541 T: Resource,
542 {
543 type Type = <&'a mut T as Join>::Type;
544 type Value = <&'a mut T as Join>::Value;
545 type Mask = <&'a mut T as Join>::Mask;
546
547 unsafe fn open(self) -> (Self::Mask, Self::Value) {
548 // SAFETY: This only wraps `T` and, while exposing the mask and
549 // the values, requires the same invariants as the original
550 // implementation and is thus safe.
551 unsafe { self.deref_mut().open() }
552 }
553
554 unsafe fn get(v: &mut Self::Value, i: Index) -> Self::Type {
555 // SAFETY: The mask of `Self` and `T` are identical, thus a
556 // check to `Self`'s mask (which is required) is equal to a
557 // check of `T`'s mask, which makes `get_mut` safe to call.
558 // Requirement to not use the same ID multiple times is passed
559 // to the caller.
560 unsafe { <&'a mut T as Join>::get(v, i) }
561 }
562
563 #[inline]
564 fn is_unconstrained() -> bool {
565 <&'a mut T as Join>::is_unconstrained()
566 }
567 }
568
569 // SAFETY: Since `T` implements `ParJoin` it is safe to deref and defer
570 // its implementation. S-TODO we can rely on errors if $ty is not sync?
571 #[cfg(feature = "parallel")]
572 unsafe impl<'a, 'b, T> ParJoin for &'a mut $ty
573 where
574 &'a mut T: ParJoin,
575 T: Resource,
576 {
577 type Type = <&'a mut T as ParJoin>::Type;
578 type Value = <&'a mut T as ParJoin>::Value;
579 type Mask = <&'a mut T as ParJoin>::Mask;
580
581 unsafe fn open(self) -> (Self::Mask, Self::Value) {
582 // SAFETY: This only wraps `T` and, while exposing the mask and
583 // the values, requires the same invariants as the original
584 // implementation and is thus safe.
585 unsafe { self.deref_mut().open() }
586 }
587
588 unsafe fn get(v: &Self::Value, i: Index) -> Self::Type {
589 // SAFETY: The mask of `Self` and `T` are identical, thus a
590 // check to `Self`'s mask (which is required) is equal to a
591 // check of `T`'s mask, which makes `get_mut` safe to call.
592 // Requirement for the return value to no longer be alive before
593 // subsequent calls with the same ID is passed to the caller.
594 unsafe { <&'a mut T as ParJoin>::get(v, i) }
595 }
596
597 #[inline]
598 fn is_unconstrained() -> bool {
599 <&'a mut T as ParJoin>::is_unconstrained()
600 }
601 }
602 )*
603 };
604}
605
606immutable_resource_join!(Fetch<'b, T>, Read<'b, T>, ReadExpect<'b, T>);
607mutable_resource_join!(FetchMut<'b, T>, Write<'b, T>, WriteExpect<'b, T>);