use std::sync::Arc;
use crossbeam_queue::SegQueue;
use futures::future::BoxFuture;
use log::warn;
use crate::{
access::WriteStorage,
component::Component,
entity::{Builder, Entity},
system::SystemData,
};
use super::World;
pub struct Lazy {
queue: Arc<SegQueue<LazyUpdate>>,
}
impl Lazy {
pub fn exec<F>(&self, f: F)
where
F: FnOnce(&mut World) + Send + Sync + 'static,
{
self.queue.push(LazyUpdate::Sync(Box::new(f)));
}
pub fn exec_async<F>(&self, f: F)
where
F: FnOnce(&mut World) -> BoxFuture<'static, ()> + Send + Sync + 'static,
{
self.queue.push(LazyUpdate::Async(Box::new(f)));
}
pub fn insert<C>(&self, e: Entity, c: C)
where
C: Component + Send + Sync,
{
self.exec(move |world| {
let mut storage: WriteStorage<C> = SystemData::fetch(world);
if storage.insert(e, c).is_err() {
warn!("Lazy insert of component failed because {:?} was dead.", e);
}
});
}
pub fn insert_many<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: WriteStorage<C> = SystemData::fetch(world);
for (e, c) in iter {
if storage.insert(e, c).is_err() {
log::warn!("Lazy insert of component failed because {:?} was dead.", e);
}
}
});
}
pub fn remove<C>(&self, e: Entity)
where
C: Component,
{
self.exec(move |world| {
let mut storage: WriteStorage<C> = SystemData::fetch(world);
storage.remove(e);
});
}
pub fn remove_many<C, I>(&self, iter: I)
where
C: Component,
I: IntoIterator<Item = Entity> + Send + Sync + 'static,
{
self.exec(move |world| {
let mut storage: WriteStorage<C> = SystemData::fetch(world);
for e in iter {
storage.remove(e);
}
});
}
pub fn create_entity(&self, world: &World) -> LazyBuilder {
let entity = world.entities().create();
LazyBuilder { entity, lazy: self }
}
pub async fn maintain(&self, world: &mut World) {
while let Some(update) = self.queue.pop() {
match update {
LazyUpdate::Sync(update) => update(world),
LazyUpdate::Async(update) => update(world).await,
}
}
}
}
impl Default for Lazy {
fn default() -> Self {
Self {
queue: Arc::new(SegQueue::new()),
}
}
}
impl Clone for Lazy {
fn clone(&self) -> Self {
Self {
queue: self.queue.clone(),
}
}
}
enum LazyUpdate {
Sync(Box<dyn FnOnce(&mut World) + Send + Sync + 'static>),
Async(Box<dyn FnOnce(&mut World) -> BoxFuture<'static, ()> + Send + Sync + 'static>),
}
pub struct LazyBuilder<'a> {
pub entity: Entity,
pub lazy: &'a Lazy,
}
impl<'a> Builder for LazyBuilder<'a> {
fn with<C>(self, component: C) -> Self
where
C: Component + Send + Sync,
{
let entity = self.entity;
self.lazy.exec(move |world| {
let mut storage: WriteStorage<C> = SystemData::fetch(world);
if storage.insert(entity, component).is_err() {
warn!(
"Lazy insert of component failed because {:?} was dead.",
entity
);
}
});
self
}
fn build(self) -> Entity {
self.entity
}
}