1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
#[nougat::gat(Type)]
use super::LendJoin;
#[cfg(feature = "parallel")]
use super::ParJoin;
use super::{Join, RepeatableLendGet};
use hibitset::{BitSetAll, BitSetLike};
use crate::world::Index;
/// Returns a structure that implements `Join`/`LendJoin`/`MaybeJoin` if the
/// contained `T` does and that yields all indices, returning `None` for all
/// missing elements and `Some(T)` for found elements.
///
/// For usage see [`LendJoin::maybe()`](LendJoin::maybe).
///
/// WARNING: Do not have a join of only `MaybeJoin`s. Otherwise the join will
/// iterate over every single index of the bitset. If you want a join with
/// all `MaybeJoin`s, add an `EntitiesRes` to the join as well to bound the
/// join to all entities that are alive.
pub struct MaybeJoin<J>(pub J);
// SAFETY: We return a mask containing all items, but check the original mask in
// the `get` implementation. Iterating the mask does not repeat indices.
#[nougat::gat]
unsafe impl<T> LendJoin for MaybeJoin<T>
where
T: LendJoin,
{
type Mask = BitSetAll;
type Type<'next> = Option<<T as LendJoin>::Type<'next>>;
type Value = (<T as LendJoin>::Mask, <T as LendJoin>::Value);
unsafe fn open(self) -> (Self::Mask, Self::Value) {
// SAFETY: While we do expose the mask and the values and therefore
// would allow swapping them, this method is `unsafe` and relies on the
// same invariants.
let (mask, value) = unsafe { self.0.open() };
(BitSetAll, (mask, value))
}
unsafe fn get<'next>((mask, value): &'next mut Self::Value, id: Index) -> Self::Type<'next> {
if mask.contains(id) {
// SAFETY: The mask was just checked for `id`. Requirement to not
// call with the same ID more than once (unless `RepeatableLendGet`
// is implemented) is passed to the caller.
Some(unsafe { <T as LendJoin>::get(value, id) })
} else {
None
}
}
#[inline]
fn is_unconstrained() -> bool {
true
}
}
// SAFETY: <MaybeJoin as LendJoin>::get does not rely on only being called once
// with a particular ID.
unsafe impl<T> RepeatableLendGet for MaybeJoin<T> where T: RepeatableLendGet {}
// SAFETY: We return a mask containing all items, but check the original mask in
// the `get` implementation. Iterating the mask does not repeat indices.
unsafe 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);
unsafe fn open(self) -> (Self::Mask, Self::Value) {
// SAFETY: While we do expose the mask and the values and therefore
// would allow swapping them, this method is `unsafe` and relies on the
// same invariants.
let (mask, value) = unsafe { self.0.open() };
(BitSetAll, (mask, value))
}
unsafe fn get((mask, value): &mut Self::Value, id: Index) -> Self::Type {
if mask.contains(id) {
// SAFETY: The mask was just checked for `id`. This has the same
// requirements on the caller to only call with the same `id` once.
Some(unsafe { <T as Join>::get(value, id) })
} else {
None
}
}
#[inline]
fn is_unconstrained() -> bool {
true
}
}
// SAFETY: This is safe as long as `T` implements `ParJoin` safely. The `get`
// implementation here makes no assumptions about being called from a single
// thread.
//
// We return a mask containing all items, but check the original mask in
// the `get` implementation. Iterating the mask does not repeat indices.
#[cfg(feature = "parallel")]
unsafe impl<T> ParJoin for MaybeJoin<T>
where
T: ParJoin,
{
type Mask = BitSetAll;
type Type = Option<<T as ParJoin>::Type>;
type Value = (<T as ParJoin>::Mask, <T as ParJoin>::Value);
unsafe fn open(self) -> (Self::Mask, Self::Value) {
// SAFETY: While we do expose the mask and the values and therefore
// would allow swapping them, this method is `unsafe` and relies on the
// same invariants.
let (mask, value) = unsafe { self.0.open() };
(BitSetAll, (mask, value))
}
unsafe fn get((mask, value): &Self::Value, id: Index) -> Self::Type {
if mask.contains(id) {
// SAFETY: The mask was just checked for `id`. This has the same
// requirements on the caller to not call with the same `id` until
// the previous value is no longer in use.
Some(unsafe { <T as ParJoin>::get(value, id) })
} else {
None
}
}
#[inline]
fn is_unconstrained() -> bool {
true
}
}