checs 0.5.1

An Entity-Component-System library.
Documentation
//! Iterating over entities and queries.

use sealed::{Bounds, Sealed};

mod sealed {
    pub trait Sealed: Sized {}
    pub struct Bounds<T>(T);
    impl<T> Sealed for Bounds<T> {}
}

/// Provides the associated item for [`LendingIterator`], similar to [`Iterator::Item`].
///
/// See [`LendingIterator`] for more.
pub trait Lifetime<'a, ImplicitBounds: Sealed = Bounds<&'a Self>> {
    /// The type of the elements being iterated over.
    type Item;
}

/// A trait similar to [`Iterator`], where the returned [`Item`]s only live until [`next`] is
/// called again.
///
/// See also: <https://sabrinajewson.org/blog/the-better-alternative-to-lifetime-gats>
///
/// # Examples
///
/// Unlike the regular [`Iterator`]s the `LendingIterator` does not support `for` loops. A `while
/// let` loop can be used instead:
///
/// ```
/// # use checs::{Lifetime, LendingIterator};
/// # struct Empty;
/// # impl Lifetime<'_> for Empty {
/// #     type Item = ();
/// # }
/// # impl LendingIterator for Empty {
/// #     fn next(&mut self) -> Option<()> {
/// #         None
/// #     }
/// # }
/// # let mut iter = Empty;
/// while let Some(item) = iter.next() {
///     println!("{item:?}");
/// }
/// ```
///
/// See [`Query`] for more examples, since it is the only type currently implementing `LendingIterator`.
///
/// [`next`]: LendingIterator::next
/// [`Item`]: Lifetime::Item
/// [`Query`]: crate::Query
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub trait LendingIterator: for<'a> Lifetime<'a> {
    /// Advances the iterator and returns the next value.
    ///
    /// The value's lifetime ends before `next` is called again.
    fn next(&mut self) -> Option<<Self as Lifetime<'_>>::Item>;

    /// Calls a closure on each element of the iterator.
    ///
    /// This is an alternative to using a `LendingIterator` in a `while let` loop.
    ///
    /// # Examples
    ///
    /// See [`Query`] for more examples, since it is the only type currently implementing
    /// `LendingIterator`.
    ///
    /// [`Query`]: crate::Query
    ///
    /// ```
    /// use checs::{ComponentVec, IntoQuery, LendingIterator};
    ///
    /// let ints: ComponentVec<i32> = ComponentVec::new();
    /// let mut floats: ComponentVec<f32> = ComponentVec::new();
    ///
    /// let query = (&ints, &mut floats).into_query();
    ///
    /// query.for_each(|(entity, (int, float))| {
    ///     println!("{entity:?}: ({int}, {float})");
    /// });
    /// ```
    #[inline]
    fn for_each<F>(mut self, mut f: F)
    where
        Self: Sized,
        F: FnMut(<Self as Lifetime>::Item),
    {
        while let Some(item) = self.next() {
            f(item);
        }
    }
}

/// An iterator over a slice that copies its values.
pub type Iter<'a, T> = std::iter::Copied<std::slice::Iter<'a, T>>;

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn iter_as_iterator() {
        let numbers = [42, 17, 99];
        let mut it: Iter<_> = numbers.iter().copied();

        assert_eq!(Iterator::next(&mut it), Some(42));
        assert_eq!(Iterator::next(&mut it), Some(17));
        assert_eq!(Iterator::next(&mut it), Some(99));
        assert_eq!(Iterator::next(&mut it), None);
    }
}