shipyard 0.6.2

Entity Component System
Documentation
use super::abstract_mut::AbstractMut;
use super::with_id::LastId;
use crate::entity_id::EntityId;
use alloc::vec::Vec;
use core::slice::Iter;
#[cfg(feature = "parallel")]
use rayon::iter::plumbing::UnindexedProducer;

#[allow(missing_docs)]
pub struct Mixed<Storage> {
    pub(super) storage: Storage,
    pub(super) indices: Iter<'static, EntityId>,
    pub(super) count: usize,
    pub(super) mask: u16,
    pub(super) last_id: EntityId,
    pub(super) rev_next_storage: Vec<Iter<'static, EntityId>>,
}

unsafe impl<Storage: Send> Send for Mixed<Storage> {}

impl<Storage: AbstractMut> Iterator for Mixed<Storage> {
    type Item = <Storage as AbstractMut>::Out;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        loop {
            for &id in self.indices.by_ref() {
                self.count += 1;

                if let Some(data_indices) = self.storage.indices_of(id, self.count - 1, self.mask) {
                    self.last_id = id;
                    return Some(unsafe { self.storage.get_datas(data_indices) });
                }
            }

            let next_indices = self.rev_next_storage.pop()?;
            self.indices = next_indices;
        }
    }
    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        (
            0,
            Some(
                self.indices.len()
                    + self
                        .rev_next_storage
                        .iter()
                        .map(|iter| iter.len())
                        .sum::<usize>(),
            ),
        )
    }
    #[inline]
    fn fold<B, F>(mut self, mut init: B, mut f: F) -> B
    where
        Self: Sized,
        F: FnMut(B, Self::Item) -> B,
    {
        loop {
            for &id in self.indices {
                self.count += 1;

                if let Some(data_indices) = self.storage.indices_of(id, self.count - 1, self.mask) {
                    self.last_id = id;
                    init = f(init, unsafe { self.storage.get_datas(data_indices) });
                }
            }

            if let Some(next_iter) = self.rev_next_storage.pop() {
                self.indices = next_iter;
            } else {
                return init;
            }
        }
    }
}

impl<Storage: AbstractMut> LastId for Mixed<Storage> {
    #[inline]
    unsafe fn last_id(&self) -> EntityId {
        self.last_id
    }
    #[inline]
    unsafe fn last_id_back(&self) -> EntityId {
        self.last_id
    }
}

#[cfg(feature = "parallel")]
impl<Storage: AbstractMut + Clone + Send> UnindexedProducer for Mixed<Storage> {
    type Item = <Storage as AbstractMut>::Out;

    #[inline]
    fn split(mut self) -> (Self, Option<Self>) {
        let len = self.indices.len();

        if len >= 2 || !self.rev_next_storage.is_empty() {
            let indices = self.indices.as_slice();
            let (first, second) = indices.split_at(indices.len() / 2);
            let second_next = self
                .rev_next_storage
                .split_off(self.rev_next_storage.len() / 2);

            let clone = Mixed {
                storage: self.storage.clone(),
                indices: second.iter(),
                count: self.count + (len / 2),
                mask: self.mask,
                last_id: self.last_id,
                rev_next_storage: second_next,
            };

            self.indices = first.iter();

            (self, Some(clone))
        } else {
            (self, None)
        }
    }

    #[inline]
    fn fold_with<F>(self, folder: F) -> F
    where
        F: rayon::iter::plumbing::Folder<Self::Item>,
    {
        folder.consume_iter(self)
    }
}