use crossbeam::sync::SegQueue;
use world::{Component, EntitiesRes, Entity, World};
struct Queue<T>(SegQueue<T>);
impl<T> Default for Queue<T> {
fn default() -> Queue<T> {
Queue(SegQueue::new())
}
}
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.exec(move |world| {
if let Err(_) = world.write_storage::<C>().insert(entity, component) {
warn!(
"Lazy insert of component failed because {:?} was dead.",
entity
);
}
});
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 {
queue: Queue<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.exec(move |world| {
if let Err(_) = world.write_storage::<C>().insert(e, c) {
warn!("Lazy insert of component failed because {:?} was dead.", e);
}
});
}
pub fn insert_all<C, I>(&self, iter: I)
where
C: Component + Send + Sync,
I: IntoIterator<Item = (Entity, C)> + Send + Sync + 'static,
{
self.exec(move |world| {
let mut storage = world.write_storage::<C>();
for (e, c) in iter {
if let Err(_) = storage.insert(e, c) {
warn!("Lazy insert of component failed because {:?} was dead.", e);
}
}
});
}
pub fn remove<C>(&self, e: Entity)
where
C: Component + Send + Sync,
{
self.exec(move |world| {
world.write_storage::<C>().remove(e);
});
}
pub fn exec<F>(&self, f: F)
where
F: FnOnce(&World) + 'static + Send + Sync,
{
self.queue.0.push(Box::new(f));
}
pub(super) fn maintain(&mut self, world: &World) {
let lazy = &mut self.queue.0;
while let Some(l) = lazy.try_pop() {
l.update(&world);
}
}
}
impl Drop for LazyUpdate {
fn drop(&mut self) {
while self.queue.0.try_pop().is_some() {}
}
}