use crate::*;
mod private {
pub trait Sealed {}
use crate::{ReadComponent, StorageSpec, WriteComponent};
impl<'a, 'b, H, T> Sealed for (&'a ReadComponent<'b, H>, T) where H: StorageSpec<'b> {}
impl<'a, 'b, H, T> Sealed for (&'a WriteComponent<'b, H>, T) where H: StorageSpec<'b> {}
impl<'a, 'b, H, T> Sealed for (&'a mut WriteComponent<'b, H>, T) where H: StorageSpec<'b> {}
impl Sealed for () {}
}
pub trait Joinable: private::Sealed {
type Output;
fn process<F>(&mut self, e: Entity, f: F)
where
F: FnOnce(Self::Output);
fn size(&self) -> usize;
}
impl<'a, 'b, H, T> Joinable for (&'a ReadComponent<'b, H>, T)
where
H: StorageSpec<'b, Component = H> + 'b,
T: Joinable,
{
type Output = (&'a H, T::Output);
fn process<F>(&mut self, e: Entity, f: F)
where
F: FnOnce(Self::Output),
{
let v = self.0.get_raw(e);
if !v.is_null() {
self.1.process(e, move |tail| f((unsafe { &*v }, tail)))
}
}
fn size(&self) -> usize {
self.0.size()
}
}
impl<'a, 'b, H, T> Joinable for (&'a WriteComponent<'b, H>, T)
where
H: StorageSpec<'b, Component = H>,
T: Joinable,
{
type Output = (&'a H, T::Output);
fn process<F>(&mut self, e: Entity, f: F)
where
F: FnOnce(Self::Output),
{
let v = self.0.get_raw(e);
if !v.is_null() {
self.1.process(e, move |tail| f((unsafe { &*v }, tail)))
}
}
fn size(&self) -> usize {
self.0.size()
}
}
impl<'a, 'b, H, T> Joinable for (&'a mut WriteComponent<'b, H>, T)
where
H: StorageSpec<'b, Component = H>,
H::Storage: MutableComponentStorage<'b>,
T: Joinable,
{
type Output = (&'a mut H, T::Output);
fn process<F>(&mut self, e: Entity, f: F)
where
F: FnOnce(Self::Output),
{
let v = self.0.get_raw_mut(e);
if !v.is_null() {
self.1.process(e, move |tail| f((unsafe { &mut *v }, tail)))
}
}
fn size(&self) -> usize {
self.0.size()
}
}
impl Joinable for () {
type Output = ();
fn process<F>(&mut self, _e: Entity, f: F)
where
F: FnOnce(()),
{
f(())
}
fn size(&self) -> usize {
0
}
}
pub trait Join {
type Output;
fn for_each<F>(self, f: F)
where
F: FnMut(Entity, Self::Output);
}
impl<T> Join for T
where
T: Nest,
T::Nested: Joinable,
<T::Nested as Joinable>::Output: Flatten,
{
type Output = <<T::Nested as Joinable>::Output as Flatten>::Flattened;
fn for_each<F>(self, mut f: F)
where
F: FnMut(Entity, Self::Output),
{
let mut storage = self.nest();
for i in 0..storage.size() {
let e = Entity {
id: i,
generation: 0,
};
storage.process(e, |v| f(e, v.flatten()));
}
}
}