async_ecs/dispatcher/
mod.rs

1pub mod builder;
2pub mod error;
3pub mod run;
4pub mod task;
5
6pub use builder::Builder;
7pub use error::Error;
8pub use run::{LocalRun, LocalRunAsync, Run, RunAsync, ThreadRun, ThreadRunAsync};
9
10use std::cell::RefCell;
11use std::ops::Deref;
12use std::ptr::null;
13use std::sync::Arc;
14
15use tokio::sync::watch::{Receiver as WatchReceiver, Sender as WatchSender};
16
17use crate::world::World;
18
19type Sender = WatchSender<()>;
20type Receiver = WatchReceiver<()>;
21
22/// The dispatcher struct, allowing
23/// systems to be executed in parallel.
24pub struct Dispatcher {
25    sender: Sender,
26    receivers: Vec<Receiver>,
27    world: SharedWorld,
28}
29
30impl Dispatcher {
31    /// Create builder to build a new dispatcher.
32    pub fn builder() -> Builder<'static> {
33        Builder::new(None)
34    }
35
36    /// Create builder to build a new dispatcher that
37    /// invokes the setup for each passed system.
38    pub fn setup_builder(world: &mut World) -> Builder<'_> {
39        Builder::new(Some(world))
40    }
41
42    /// Dispatch all the systems with given resources and context
43    /// and then run thread local systems.
44    ///
45    /// Please note that this method assumes that no resource
46    /// is currently borrowed. If that's the case, it panics.
47    pub async fn dispatch(&mut self, world: &World) -> Result<(), Error> {
48        let _guard = self.world.set(world);
49
50        match self.sender.send(()) {
51            Ok(()) => (),
52            Err(_) => return Err(Error::DispatchSend),
53        }
54
55        for receiver in &mut self.receivers {
56            match receiver.changed().await {
57                Ok(()) => (),
58                Err(_) => return Err(Error::DispatchReceive),
59            }
60        }
61
62        Ok(())
63    }
64}
65
66/// Helper type to share the world parameter passed to `Dispatcher::dispatch`.
67#[derive(Clone)]
68pub struct SharedWorld(Arc<RefCell<*const World>>);
69
70impl SharedWorld {
71    fn set(&mut self, world: &World) -> WorldGuard {
72        *self.0.borrow_mut() = world as *const _;
73
74        WorldGuard(self)
75    }
76
77    fn clear(&mut self) {
78        *self.0.borrow_mut() = null();
79    }
80}
81
82unsafe impl Send for SharedWorld {}
83unsafe impl Sync for SharedWorld {}
84
85impl Default for SharedWorld {
86    fn default() -> Self {
87        Self(Arc::new(RefCell::new(null())))
88    }
89}
90
91impl Deref for SharedWorld {
92    type Target = World;
93
94    fn deref(&self) -> &Self::Target {
95        let world = self.0.borrow();
96
97        if world.is_null() {
98            panic!("No World assigned!");
99        }
100
101        unsafe { &**world }
102    }
103}
104
105/// Guard to share the world parameter passed to `Dispatcher::dispatch`.
106struct WorldGuard<'a>(&'a mut SharedWorld);
107
108impl Drop for WorldGuard<'_> {
109    fn drop(&mut self) {
110        self.0.clear()
111    }
112}