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
    }
}