use crossbeam::sync::TreiberStack;
use world::{Component, EntitiesRes, Entity, World};
pub struct LazyBuilder<'a> {
pub entity: Entity,
pub lazy: &'a LazyUpdate,
}
impl<'a> LazyBuilder<'a> {
pub fn with<C>(self, component: C) -> Self
where
C: Component + Send + Sync,
{
let entity = self.entity;
self.lazy.execute(move |world| {
world.write_storage::<C>().insert(entity, component);
});
self
}
pub fn build(self) -> Entity {
self.entity
}
}
trait LazyUpdateInternal: Send + Sync {
fn update(self: Box<Self>, world: &World);
}
impl<F> LazyUpdateInternal for F
where
F: FnOnce(&World) + Send + Sync + 'static,
{
fn update(self: Box<Self>, world: &World) {
self(world);
}
}
#[derive(Default)]
pub struct LazyUpdate {
stack: TreiberStack<Box<LazyUpdateInternal>>,
}
impl LazyUpdate {
pub fn create_entity(&self, ent: &EntitiesRes) -> LazyBuilder {
let entity = ent.create();
LazyBuilder { entity, lazy: self }
}
pub fn insert<C>(&self, e: Entity, c: C)
where
C: Component + Send + Sync,
{
self.execute(move |world| {
world.write_storage::<C>().insert(e, c);
});
}
pub fn insert_all<C, I>(&self, iter: I)
where
C: Component + Send + Sync,
I: IntoIterator<Item = (Entity, C)> + Send + Sync + 'static,
{
self.execute(move |world| {
let mut storage = world.write_storage::<C>();
for (e, c) in iter {
storage.insert(e, c);
}
});
}
pub fn remove<C>(&self, e: Entity)
where
C: Component + Send + Sync,
{
self.execute(move |world| {
world.write_storage::<C>().remove(e);
});
}
pub fn execute<F>(&self, f: F)
where
F: FnOnce(&World) + 'static + Send + Sync,
{
self.stack.push(Box::new(f));
}
pub(super) fn maintain(&mut self, world: &World) {
let lazy = &mut self.stack;
while let Some(l) = lazy.pop() {
l.update(&world);
}
}
}
impl Drop for LazyUpdate {
fn drop(&mut self) {
while self.stack.pop().is_some() {}
}
}