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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
use super::MaybeJoin;
use hibitset::{BitIter, BitSetLike};

use crate::world::{Entities, Entity, Index};

/// Like the [`Join`](super::Join) trait except this is similar to a [lending
/// iterator](https://blog.rust-lang.org/2021/08/03/GATs-stabilization-push.html#so-what-are-gats)
/// in that only one item can be accessed at once.
///
/// The type returned from [`.lend_join()`](LendJoin::lend_join),
/// [`JoinLendIter`] does not implement `Iterator` like
/// [`JoinIter`](super::JoinIter) does. Instead, it provides a
/// [`next`](JoinLendIter::next) method that exclusively borrows the
/// `JoinLendIter` for the lifetime of the returned value.
///
/// This limitation allows freedom for more patterns to be soundly implemented.
/// Thus, `LendJoin` acts as the "lowest common denominator" of the
/// `Join`-like traits (i.e. if something can implement `Join` it can also
/// implement `LendJoin`).
///
/// In particular, [`Entries`](crate::storage::Entries) only implements
/// `LendJoin`. As another example,
/// [`RestrictedStorage`](crate::storage::RestrictedStorage) implements both
/// `Join` and `LendJoin`. However, for joining mutably, lend join variant
/// produces
/// [`PairedStorageWriteExclusive`](crate::storage::PairedStorageWriteExclusive)
/// values which have `get_other`/`get_other_mut` methods that aren't provided
/// by [`PairedStorageWriteShared`](crate::storage::PairedStorageWriteShared).
///
/// Finally, these limitations allow providing the [`JoinLendIter::get`] method
/// which can be useful to get a set of components from an entity without
/// calling `get` individually on each storage (see the example in that method's
/// docs).
///
/// Also see the `lend_join` example.
///
/// # Safety
///
/// The `Self::Mask` value returned with the `Self::Value` must correspond such
/// that it is safe to retrieve items from `Self::Value` whose presence is
/// indicated in the mask. As part of this, `BitSetLike::iter` must not produce
/// an iterator that repeats an `Index` value if the `LendJoin::get` impl relies
/// on not being called twice with the same `Index`.
#[nougat::gat]
pub unsafe trait LendJoin {
    /// Type of joined components.
    ///
    /// # Note
    ///
    /// This type is using macro magic to emulate GATs on stable. So to refer to
    /// it you need to use the [`LendJoinType<'next, J>`](LendJoinType) type
    /// alias.
    type Type<'next>
    where
        Self: 'next;
    /// Type of joined storages.
    type Value;
    /// Type of joined bit mask.
    type Mask: BitSetLike;

    /// Create a joined lending iterator over the contents.
    fn lend_join(self) -> JoinLendIter<Self>
    where
        Self: Sized,
    {
        JoinLendIter::new(self)
    }

    /// 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.
    ///
    /// To join over and optional component mutably this pattern can be used:
    /// `(&mut storage).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.
    ///
    /// ```
    /// # use specs::prelude::*;
    /// # #[derive(Debug, PartialEq)]
    /// # struct Pos { x: i32, y: i32 } impl Component for Pos { type Storage = VecStorage<Self>; }
    /// # #[derive(Debug, PartialEq)]
    /// # struct Vel { x: i32, y: i32 } impl Component for Vel { type Storage = VecStorage<Self>; }
    /// struct ExampleSystem;
    /// impl<'a> System<'a> for ExampleSystem {
    ///     type SystemData = (
    ///         WriteStorage<'a, Pos>,
    ///         ReadStorage<'a, Vel>,
    ///     );
    ///     fn run(&mut self, (mut positions, velocities): Self::SystemData) {
    ///         let mut join = (&mut positions, velocities.maybe()).lend_join();
    ///         while let Some ((mut position, maybe_velocity)) = join.next() {
    ///             if let Some(velocity) = maybe_velocity {
    ///                 position.x += velocity.x;
    ///                 position.y += velocity.y;
    ///             }
    ///         }
    ///     }
    /// }
    ///
    /// fn main() {
    ///     let mut world = World::new();
    ///     let mut dispatcher = DispatcherBuilder::new()
    ///         .with(ExampleSystem, "example_system", &[])
    ///         .build();
    ///
    ///     dispatcher.setup(&mut world);
    ///
    ///     let e1 = world.create_entity()
    ///         .with(Pos { x: 0, y: 0 })
    ///         .with(Vel { x: 5, y: 2 })
    ///         .build();
    ///
    ///     let e2 = world.create_entity()
    ///         .with(Pos { x: 0, y: 0 })
    ///         .build();
    ///
    ///     dispatcher.dispatch(&mut world);
    ///
    ///     let positions = world.read_storage::<Pos>();
    ///     assert_eq!(positions.get(e1), Some(&Pos { x: 5, y: 2 }));
    ///     assert_eq!(positions.get(e2), Some(&Pos { x: 0, y: 0 }));
    /// }
    /// ```
    fn maybe(self) -> MaybeJoin<Self>
    where
        Self: Sized,
    {
        MaybeJoin(self)
    }

    /// Open this join by returning the mask and the storages.
    ///
    /// # Safety
    ///
    /// This is unsafe because implementations of this trait can permit the
    /// `Value` to be mutated independently of the `Mask`. If the `Mask` does
    /// not correctly report the status of the `Value` then illegal memory
    /// access can occur.
    unsafe fn open(self) -> (Self::Mask, Self::Value);

    /// Get a joined component value by a given index.
    ///
    /// # Safety
    ///
    /// * A call to `get` must be preceded by a check if `id` is part of
    ///   `Self::Mask`
    /// * Multiple calls with the same `id` are not allowed, for a particular
    ///   instance of the values from [`open`](LendJoin::open). Unless this type
    ///   implements the unsafe trait [`RepeatableLendGet`].
    unsafe fn get<'next>(value: &'next mut Self::Value, id: Index) -> Self::Type<'next>;

    /// If this `LendJoin` typically returns all indices in the mask, then
    /// iterating over only it or combined with other joins that are also
    /// dangerous will cause the `JoinLendIter` to go through all indices which
    /// is usually not what is wanted and will kill performance.
    #[inline]
    fn is_unconstrained() -> bool {
        false
    }
}

/// # Safety
///
/// Implementing this trait guarantees that `<Self as LendJoin>::get` can
/// soundly be called multiple times with the same ID.
pub unsafe trait RepeatableLendGet: LendJoin {}

/// Type alias to refer to the `<J as LendJoin>::Type<'next>` (except this
/// doesn't actually exist in this form so the `nougat::Gat!` macro is needed).
pub type LendJoinType<'next, J> = nougat::Gat!(<J as LendJoin>::Type<'next>);

/// `JoinLendIter` is an is a lending/streaming iterator over components from a
/// group of storages.
#[must_use]
pub struct JoinLendIter<J: LendJoin> {
    keys: BitIter<J::Mask>,
    values: J::Value,
}

impl<J: LendJoin> JoinLendIter<J> {
    /// Create a new lending join iterator.
    pub fn new(j: J) -> Self {
        if <J as LendJoin>::is_unconstrained() {
            log::warn!(
                "`LendJoin` possibly iterating through all indices, \
                you might've made a join with all `MaybeJoin`s, \
                which is unbounded in length."
            );
        }

        // SAFETY: We do not swap out the mask or the values, nor do we allow it
        // by exposing them.
        let (keys, values) = unsafe { j.open() };
        JoinLendIter {
            keys: keys.iter(),
            values,
        }
    }
}

impl<J: LendJoin> JoinLendIter<J> {
    /// Lending `next`.
    ///
    /// Can be used to iterate with this pattern:
    ///
    /// `while let Some(components) = join_lending_iter.next() {`
    #[allow(clippy::should_implement_trait)] // we want this to look like iterator
    pub fn next(&mut self) -> Option<LendJoinType<'_, J>> {
        // SAFETY: Since `idx` is yielded from `keys` (the mask), it is
        // necessarily a part of it. `LendJoin` requires that the iterator
        // doesn't repeat indices and we advance the iterator for each `get`
        // call in all methods that don't require `RepeatableLendGet`.
        self.keys
            .next()
            .map(|idx| unsafe { J::get(&mut self.values, idx) })
    }

    /// Calls a closure on each entity in the join.
    pub fn for_each(mut self, mut f: impl FnMut(LendJoinType<'_, J>)) {
        self.keys.for_each(|idx| {
            // SAFETY: Since `idx` is yielded from `keys` (the mask), it is
            // necessarily a part of it. `LendJoin` requires that the iterator
            // doesn't repeat indices and we advance the iterator for each `get`
            // call in all methods that don't require `RepeatableLendGet`.
            let item = unsafe { J::get(&mut self.values, idx) };
            f(item);
        })
    }

    /// Allows getting joined values for specific entity.
    ///
    /// ## Example
    ///
    /// ```
    /// # use specs::prelude::*;
    /// # #[derive(Debug, PartialEq)]
    /// # struct Pos; impl Component for Pos { type Storage = VecStorage<Self>; }
    /// # #[derive(Debug, PartialEq)]
    /// # struct Vel; impl Component for Vel { type Storage = VecStorage<Self>; }
    /// let mut world = World::new();
    ///
    /// world.register::<Pos>();
    /// world.register::<Vel>();
    ///
    /// // This entity could be stashed anywhere (into `Component`, `Resource`, `System`s data, etc.) as it's just a number.
    /// let entity = world
    ///     .create_entity()
    ///     .with(Pos)
    ///     .with(Vel)
    ///     .build();
    ///
    /// // Later
    /// {
    ///     let mut pos = world.write_storage::<Pos>();
    ///     let vel = world.read_storage::<Vel>();
    ///
    ///     assert_eq!(
    ///         Some((&mut Pos, &Vel)),
    ///         (&mut pos, &vel).lend_join().get(entity, &world.entities()),
    ///         "The entity that was stashed still has the needed components and is alive."
    ///     );
    /// }
    ///
    /// // The entity has found nice spot and doesn't need to move anymore.
    /// world.write_storage::<Vel>().remove(entity);
    ///
    /// // Even later
    /// {
    ///     let mut pos = world.write_storage::<Pos>();
    ///     let vel = world.read_storage::<Vel>();
    ///
    ///     assert_eq!(
    ///         None,
    ///         (&mut pos, &vel).lend_join().get(entity, &world.entities()),
    ///         "The entity doesn't have velocity anymore."
    ///     );
    /// }
    /// ```
    pub fn get(&mut self, entity: Entity, entities: &Entities) -> Option<LendJoinType<'_, J>>
    where
        J: RepeatableLendGet,
    {
        if self.keys.contains(entity.id()) && entities.is_alive(entity) {
            // SAFETY: the mask (`keys`) is checked as specified in the docs of
            // `get`. We require `J: RepeatableJoinGet` so this can be safely
            // called multiple time with the same ID.
            Some(unsafe { J::get(&mut self.values, entity.id()) })
        } else {
            None
        }
    }

    /// Allows getting joined values for specific raw index.
    ///
    /// The raw index for an `Entity` can be retrieved using `Entity::id`
    /// method.
    ///
    /// As this method operates on raw indices, there is no check to see if the
    /// entity is still alive, so the caller should ensure it instead.
    ///
    /// Note: Not checking is still sound (thus this method is safe to call),
    /// but this can return data from deleted entities!
    pub fn get_unchecked(&mut self, index: Index) -> Option<LendJoinType<'_, J>>
    where
        J: RepeatableLendGet,
    {
        if self.keys.contains(index) {
            // SAFETY: the mask (`keys`) is checked as specified in the docs of
            // `get`. We require `J: RepeatableJoinGet` so this can be safely
            // called multiple time with the same ID.
            Some(unsafe { J::get(&mut self.values, index) })
        } else {
            None
        }
    }
}