checs/iter.rs
1//! Iterating over entities and queries.
2
3use sealed::{Bounds, Sealed};
4
5mod sealed {
6 pub trait Sealed: Sized {}
7 pub struct Bounds<T>(T);
8 impl<T> Sealed for Bounds<T> {}
9}
10
11/// Provides the associated item for [`LendingIterator`], similar to [`Iterator::Item`].
12///
13/// See [`LendingIterator`] for more.
14pub trait Lifetime<'a, ImplicitBounds: Sealed = Bounds<&'a Self>> {
15 /// The type of the elements being iterated over.
16 type Item;
17}
18
19/// A trait similar to [`Iterator`], where the returned [`Item`]s only live until [`next`] is
20/// called again.
21///
22/// See also: <https://sabrinajewson.org/blog/the-better-alternative-to-lifetime-gats>
23///
24/// # Examples
25///
26/// Unlike the regular [`Iterator`]s the `LendingIterator` does not support `for` loops. A `while
27/// let` loop can be used instead:
28///
29/// ```
30/// # use checs::{Lifetime, LendingIterator};
31/// # struct Empty;
32/// # impl Lifetime<'_> for Empty {
33/// # type Item = ();
34/// # }
35/// # impl LendingIterator for Empty {
36/// # fn next(&mut self) -> Option<()> {
37/// # None
38/// # }
39/// # }
40/// # let mut iter = Empty;
41/// while let Some(item) = iter.next() {
42/// println!("{item:?}");
43/// }
44/// ```
45///
46/// See [`Query`] for more examples, since it is the only type currently implementing `LendingIterator`.
47///
48/// [`next`]: LendingIterator::next
49/// [`Item`]: Lifetime::Item
50/// [`Query`]: crate::Query
51#[must_use = "iterators are lazy and do nothing unless consumed"]
52pub trait LendingIterator: for<'a> Lifetime<'a> {
53 /// Advances the iterator and returns the next value.
54 ///
55 /// The value's lifetime ends before `next` is called again.
56 fn next(&mut self) -> Option<<Self as Lifetime<'_>>::Item>;
57
58 /// Calls a closure on each element of the iterator.
59 ///
60 /// This is an alternative to using a `LendingIterator` in a `while let` loop.
61 ///
62 /// # Examples
63 ///
64 /// See [`Query`] for more examples, since it is the only type currently implementing
65 /// `LendingIterator`.
66 ///
67 /// [`Query`]: crate::Query
68 ///
69 /// ```
70 /// use checs::{ComponentVec, IntoQuery, LendingIterator};
71 ///
72 /// let ints: ComponentVec<i32> = ComponentVec::new();
73 /// let mut floats: ComponentVec<f32> = ComponentVec::new();
74 ///
75 /// let query = (&ints, &mut floats).into_query();
76 ///
77 /// query.for_each(|(entity, (int, float))| {
78 /// println!("{entity:?}: ({int}, {float})");
79 /// });
80 /// ```
81 #[inline]
82 fn for_each<F>(mut self, mut f: F)
83 where
84 Self: Sized,
85 F: FnMut(<Self as Lifetime>::Item),
86 {
87 while let Some(item) = self.next() {
88 f(item);
89 }
90 }
91}
92
93/// An iterator over a slice that copies its values.
94pub type Iter<'a, T> = std::iter::Copied<std::slice::Iter<'a, T>>;
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99
100 #[test]
101 fn iter_as_iterator() {
102 let numbers = [42, 17, 99];
103 let mut it: Iter<_> = numbers.iter().copied();
104
105 assert_eq!(Iterator::next(&mut it), Some(42));
106 assert_eq!(Iterator::next(&mut it), Some(17));
107 assert_eq!(Iterator::next(&mut it), Some(99));
108 assert_eq!(Iterator::next(&mut it), None);
109 }
110}