checs 0.5.1

An Entity-Component-System library.
Documentation
//! Intersections of entity sets.

use crate::entity;
use crate::sparse;

/// An iterator adapter that creates an
/// [intersection](https://en.wikipedia.org/wiki/Intersection_(set_theory)) with a [`sparse::Set`].
///
/// The returned iterator will only yield entities that are also contained in the set.
///
/// The `struct` is created by calling the [`intersect`] method on an iterator, or by using
/// [`Intersection::new`].
///
/// [`intersect`]: Intersect::intersect
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct Intersection<'a, I> {
    iter: I,
    set: &'a sparse::Set,
}

impl<'a, I> Intersection<'a, I> {
    /// Constructs a new `Intersection`.
    #[inline]
    pub fn new(iter: I, set: &'a sparse::Set) -> Self {
        Self { iter, set }
    }
}

impl<I> Iterator for Intersection<'_, I>
where
    I: Iterator<Item = entity::Entity>,
{
    type Item = I::Item;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        while let Some(current) = self.iter.next() {
            if self.set.contains(current) {
                return Some(current);
            }
        }

        None
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let (_, upper) = self.iter.size_hint();
        (0, upper)
    }
}

impl<I> std::iter::FusedIterator for Intersection<'_, I> where
    I: std::iter::FusedIterator<Item = entity::Entity>
{
}

/// A trait that extends the `Iterator` trait with a method to create an [`Intersection`].
pub trait Intersect<'a>: Sized + Iterator<Item = entity::Entity> {
    /// Takes a `set` and creates an iterator which only yields entities that are also contained in
    /// the `set`.
    fn intersect(self, set: &'a sparse::Set) -> Intersection<'a, Self>;
}

impl<'a, I> Intersect<'a> for I
where
    I: Iterator<Item = entity::Entity>,
{
    #[inline]
    fn intersect(self, set: &'a sparse::Set) -> Intersection<'a, Self> {
        Intersection::new(self, set)
    }
}

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

    #[test]
    fn intersection() {
        let mut set1 = sparse::Set::new();

        set1.insert(Entity::from(42));
        set1.insert(Entity::from(99));
        set1.insert(Entity::from(0));
        set1.insert(Entity::from(1));
        set1.insert(Entity::from(17));

        let mut set2 = sparse::Set::new();

        set2.insert(Entity::from(17));
        set2.insert(Entity::from(99));
        set2.insert(Entity::from(43));
        set2.insert(Entity::from(3));
        set2.insert(Entity::from(1));
        set2.insert(Entity::from(100));

        let mut it = Intersection::new(set1.iter(), &set2);

        assert_eq!(it.size_hint(), (0, Some(5)));
        assert_eq!(it.next(), Some(Entity::from(99)));

        assert_eq!(it.size_hint(), (0, Some(3)));
        assert_eq!(it.next(), Some(Entity::from(1)));

        assert_eq!(it.size_hint(), (0, Some(1)));
        assert_eq!(it.next(), Some(Entity::from(17)));

        assert_eq!(it.size_hint(), (0, Some(0)));
        assert_eq!(it.next(), None);

        assert_eq!(it.size_hint(), (0, Some(0)));
        assert_eq!(it.next(), None);

        let mut it = set2.iter().intersect(&set1);

        assert_eq!(it.next(), Some(Entity::from(17)));
        assert_eq!(it.next(), Some(Entity::from(99)));
        assert_eq!(it.next(), Some(Entity::from(1)));
        assert_eq!(it.next(), None);

        let mut set3 = sparse::Set::new();

        set3.insert(Entity::from(1000));
        set3.insert(Entity::from(1001));
        set3.insert(Entity::from(1002));
        set3.insert(Entity::from(1003));
        set3.insert(Entity::from(1004));
        set3.insert(Entity::from(1005));
        set3.insert(Entity::from(1006));

        let mut it = set1.iter().intersect(&set2).intersect(&set3);
        assert_eq!(it.next(), None);

        set3.insert(Entity::from(17));
        set3.insert(Entity::from(1));

        let mut it = set1.iter().intersect(&set2).intersect(&set3);
        assert_eq!(it.next(), Some(Entity::from(1)));
        assert_eq!(it.next(), Some(Entity::from(17)));
        assert_eq!(it.next(), None);
    }
}