Skip to content

Commit c45239f

Browse files
committed
added Facade::visit_world_mut, World::remove_node
1 parent 44efc69 commit c45239f

4 files changed

Lines changed: 69 additions & 17 deletions

File tree

crates/apecs/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "apecs"
3-
version = "0.8.3"
3+
version = "0.8.4"
44
edition = "2021"
55
license = "MIT OR Apache-2.0"
66
keywords = ["gamedev", "ecs", "async"]
@@ -26,7 +26,7 @@ bench = false
2626
any_vec = "0.10"
2727
apecs-derive = { version = "0.3.0", path = "../apecs-derive" }
2828
async-channel = "1.6"
29-
moongraph = { version = "0.4.2", default-features = false, features = ["parallel"] }
29+
moongraph = { version = "0.4.3", default-features = false, features = ["parallel"] }
3030
itertools = "0.10"
3131
log = "0.4"
3232
parking_lot = "0.12"

crates/apecs/src/facade.rs

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
//! Access the [`World`]s resources from async futures.
2+
use std::{any::Any, sync::Arc};
3+
24
use moongraph::{Edges, Function, GraphError, Node, Resource, TypeKey, TypeMap};
35

6+
use crate::{world::LazyOp, World};
7+
48
pub(crate) struct Request {
59
pub(crate) reads: Vec<TypeKey>,
610
pub(crate) writes: Vec<TypeKey>,
@@ -45,6 +49,7 @@ pub struct Facade {
4549
// Unbounded. Sending a request from the facade will not yield the future.
4650
// In other words, it will not cause the async to stop at an await point.
4751
pub(crate) request_tx: async_channel::Sender<Request>,
52+
pub(crate) lazy_tx: async_channel::Sender<LazyOp>,
4853
}
4954

5055
impl Facade {
@@ -71,7 +76,7 @@ impl Facade {
7176
writes,
7277
moves,
7378
prepare: |resources: &mut TypeMap| {
74-
log::trace!(
79+
log::debug!(
7580
"request got resources - constructing {}",
7681
std::any::type_name::<D>()
7782
);
@@ -87,14 +92,41 @@ impl Facade {
8792
let box_d: Box<D> = rez.downcast().unwrap();
8893
let d = *box_d;
8994
let t = f(d);
90-
log::trace!("request for {} done", std::any::type_name::<D>());
95+
log::debug!("request for {} done", std::any::type_name::<D>());
9196
Ok(t)
9297
}
9398

9499
/// Return the total number of facades.
95100
pub fn count(&self) -> usize {
96101
self.request_tx.sender_count()
97102
}
103+
104+
pub async fn visit_world_mut<T>(
105+
&mut self,
106+
f: impl FnOnce(&mut World) -> T + Send + Sync + 'static,
107+
) -> Result<T, GraphError>
108+
where
109+
T: Any + Send + Sync,
110+
{
111+
let (tx, rx) = async_channel::bounded(1);
112+
// UNWRAP: safe because this channel is unbounded
113+
self.lazy_tx
114+
.try_send(LazyOp {
115+
op: Box::new(|world| {
116+
let t = f(world);
117+
let any_t = Arc::new(t);
118+
Ok(any_t)
119+
}),
120+
tx,
121+
})
122+
.unwrap();
123+
let any_t: Arc<_> = rx.recv().await.map_err(GraphError::other)?;
124+
// UNWRAP: safe because we know we will only receive the type we expect, as we packed it
125+
// in the closure above.
126+
let arc_t: Arc<T> = any_t.downcast().unwrap();
127+
// UNWRAP: safe because we know nothing has cloned this arc
128+
Ok(Arc::try_unwrap(arc_t).unwrap_or_else(|_| unreachable!("something cloned the arc")))
129+
}
98130
}
99131

100132
/// A fulfillment schedule of requests for world resources,
@@ -142,6 +174,10 @@ impl<'a> FacadeSchedule<'a> {
142174
self.batches.len()
143175
}
144176

177+
pub fn is_empty(&self) -> bool {
178+
self.len() == 0
179+
}
180+
145181
/// Attempt to unify resources, returning `true` if resources are unified, `false` if not.
146182
pub fn unify(&mut self) -> bool {
147183
self.batches.unify()

crates/apecs/src/storage/archetype/components.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -429,21 +429,23 @@ impl Components {
429429
}
430430
}
431431

432+
type LazyComponentUpdate = Box<dyn FnOnce(&mut Components) + Send + Sync + 'static>;
433+
432434
/// Add components lazily, at the time of your choosing.
433435
///
434436
/// Used in instances where you can't apply changes to Components because of a
435437
/// borrow conflict (eg while iterating over a component query).
436438
#[derive(Default)]
437-
pub struct LazyComponents(Vec<Box<dyn FnOnce(&mut Components)>>);
439+
pub struct LazyComponents(Vec<LazyComponentUpdate>);
438440

439-
impl Extend<Box<dyn FnOnce(&mut Components)>> for LazyComponents {
440-
fn extend<T: IntoIterator<Item = Box<dyn FnOnce(&mut Components)>>>(&mut self, iter: T) {
441+
impl Extend<LazyComponentUpdate> for LazyComponents {
442+
fn extend<T: IntoIterator<Item = LazyComponentUpdate>>(&mut self, iter: T) {
441443
self.0.extend(iter);
442444
}
443445
}
444446

445447
impl IntoIterator for LazyComponents {
446-
type Item = Box<dyn FnOnce(&mut Components)>;
448+
type Item = LazyComponentUpdate;
447449

448450
type IntoIter = std::vec::IntoIter<Self::Item>;
449451

@@ -454,7 +456,11 @@ impl IntoIterator for LazyComponents {
454456

455457
impl LazyComponents {
456458
/// Inserts the bundled components for the given entity.
457-
pub fn insert_bundle<B: IsBundle + 'static>(&mut self, entity_id: usize, bundle: B) {
459+
pub fn insert_bundle<B: IsBundle + Send + Sync + 'static>(
460+
&mut self,
461+
entity_id: usize,
462+
bundle: B,
463+
) {
458464
self.0.push(Box::new(move |components| {
459465
components.insert_bundle(entity_id, bundle)
460466
}));
@@ -475,8 +481,7 @@ impl LazyComponents {
475481
}));
476482
}
477483

478-
/// Remove a single component from the given entity, returning it if the
479-
/// entity had a component of that type.
484+
/// Remove a single component from the given entity.
480485
pub fn remove_component<T: Send + Sync + 'static>(&mut self, entity_id: usize) {
481486
self.0.push(Box::new(move |components| {
482487
components.remove_component::<T>(entity_id);

crates/apecs/src/world.rs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,16 +62,14 @@ impl EntityUpkeepSystem {
6262
fn tick(mut self) -> Result<(), GraphError> {
6363
let dead_ids: Vec<usize> = {
6464
let mut dead_ids = vec![];
65-
while let Some(id) = self.entities.delete_rx.try_recv().ok() {
65+
while let Ok(id) = self.entities.delete_rx.try_recv() {
6666
dead_ids.push(id);
6767
}
6868
dead_ids
6969
};
7070
if !dead_ids.is_empty() {
71-
let ids_and_types: Vec<(usize, smallvec::SmallVec<[TypeId; 4]>)> = {
72-
let ids_and_types = self.components.upkeep(&dead_ids);
73-
ids_and_types
74-
};
71+
let ids_and_types: Vec<(usize, smallvec::SmallVec<[TypeId; 4]>)> =
72+
{ self.components.upkeep(&dead_ids) };
7573
self.entities
7674
.recycle
7775
.extend(ids_and_types.iter().map(|(id, _)| *id));
@@ -228,7 +226,10 @@ impl Default for World {
228226
let lazy_ops = async_channel::unbounded();
229227
let entities = Entities::new(lazy_ops.0.clone());
230228
let (tx, rx) = async_channel::unbounded();
231-
let facade = Facade { request_tx: tx };
229+
let facade = Facade {
230+
request_tx: tx,
231+
lazy_tx: lazy_ops.0.clone(),
232+
};
232233
let mut world = Self {
233234
graph: Graph::default(),
234235
facade: facade.clone(),
@@ -268,6 +269,16 @@ impl World {
268269
self
269270
}
270271

272+
pub fn remove_node(&mut self, name: impl AsRef<str>) {
273+
let _ = self.graph.remove_node(name);
274+
}
275+
276+
pub fn remove_nodes<T: AsRef<str>>(&mut self, names: impl IntoIterator<Item = T>) {
277+
for name in names.into_iter() {
278+
self.remove_node(name);
279+
}
280+
}
281+
271282
pub fn interleave_subgraph(&mut self, graph: Graph) -> &mut Self {
272283
self.graph.interleave_subgraph(graph);
273284
let _ = self.graph.reschedule_if_necessary();

0 commit comments

Comments
 (0)