1use std::sync::atomic::{AtomicBool, Ordering};
4
5use crossbeam::channel;
6use downcast::{downcast, Any};
7
8use crate::{
9 entities::EntityLiveness,
10 prelude::{
11 AccessDispatcher, AccessEntityStats, AccessQuery, AccessResources,
12 AccessSpawnEntities, Component, Entity, EntityBuilder, Query, World,
13 },
14 resource::{ReadResource, Resource, ResourceLookupError, WriteResource},
15 world::{dispatch_inner, LazyUpdate},
16};
17
18pub trait Message: Any {}
24downcast!(dyn Message);
25
26pub type MsgHandlerRead<C, E> =
28 fn(this: &C, event: E, owner: Entity, access: &ListenerWorldAccess) -> E;
29pub type MsgHandlerWrite<C, E> =
31 fn(this: &mut C, event: E, owner: Entity, access: &ListenerWorldAccess) -> E;
32
33pub(crate) enum MsgHandlerInner {
34 Read(
35 Box<
36 dyn Send
37 + Sync
38 + Fn(
39 &dyn Component,
40 Box<dyn Message>,
41 Entity,
42 &ListenerWorldAccess,
43 ) -> Box<dyn Message>,
44 >,
45 ),
46 Write(
47 Box<
48 dyn Send
49 + Sync
50 + Fn(
51 &mut dyn Component,
52 Box<dyn Message>,
53 Entity,
54 &ListenerWorldAccess,
55 ) -> Box<dyn Message>,
56 >,
57 ),
58}
59
60pub struct ListenerWorldAccess<'w> {
64 lazy_updates: channel::Sender<LazyUpdate>,
65 queued_message_tx: channel::Sender<(Box<dyn Message>, Entity)>,
66 queued_message_rx: channel::Receiver<(Box<dyn Message>, Entity)>,
67 cancelled: AtomicBool,
68
69 pub(crate) world: &'w World,
70}
71
72impl<'w> ListenerWorldAccess<'w> {
73 pub(crate) fn new(world: &'w World) -> Self {
74 let (tx, rx) = channel::unbounded();
75 Self {
76 lazy_updates: world.lazy_sender.clone(),
77 queued_message_tx: tx,
78 queued_message_rx: rx,
79 cancelled: AtomicBool::new(false),
80 world,
81 }
82 }
83
84 pub fn queue_dispatch<M: Message>(&self, target: Entity, msg: M) {
91 self
92 .queued_message_tx
93 .send((Box::new(msg), target))
94 .unwrap();
95 }
96
97 pub fn lazy_spawn<'a>(&'a self) -> EntityBuilder<'a, 'w> {
99 let entity = self.world.entities.spawn_unfinished();
100 EntityBuilder::new_lazy(self, entity)
101 }
102
103 pub fn lazy_despawn(&self, entity: Entity) {
105 self.queue_update(LazyUpdate::DespawnEntity(entity));
106 }
107
108 pub fn cancel(&self) {
113 self.set_cancellation(true)
114 }
115
116 pub fn set_cancellation(&self, cancelled: bool) {
118 self.cancelled.store(cancelled, Ordering::Relaxed);
119 }
120
121 pub fn is_cancelled(&self) -> bool {
126 self.cancelled.load(Ordering::SeqCst)
127 }
128
129 pub(crate) fn queue_update(&self, update: LazyUpdate) {
130 self.lazy_updates.send(update).unwrap();
131 }
132
133 pub(crate) fn queued_message_rx(
134 &self,
135 ) -> &channel::Receiver<(Box<dyn Message>, Entity)> {
136 &self.queued_message_rx
137 }
138}
139
140impl<'w> AccessDispatcher for ListenerWorldAccess<'w> {
141 fn dispatch<M: Message>(&self, target: Entity, msg: M) -> M {
142 dispatch_inner(self, target, msg)
143 }
144}
145
146impl<'w> AccessEntityStats for ListenerWorldAccess<'w> {
147 fn len(&self) -> usize {
148 self.world.len()
149 }
150
151 fn liveness(&self, entity: Entity) -> EntityLiveness {
152 self.world.liveness(entity)
153 }
154
155 fn len_of(&self, entity: Entity) -> usize {
156 self.world.len_of(entity)
157 }
158
159 fn iter(&self) -> crate::entities::EntityIter<'_> {
160 self.world.iter()
161 }
162}
163
164impl<'w> AccessQuery for ListenerWorldAccess<'w> {
165 fn query<'c, Q: Query<'c>>(
166 &'c self,
167 interrogatee: Entity,
168 ) -> Option<Q::Response> {
169 self.world.query::<Q>(interrogatee)
170 }
171}
172
173impl<'w> AccessResources for ListenerWorldAccess<'w> {
174 fn read_resource<R: Resource>(
175 &self,
176 ) -> Result<ReadResource<'_, R>, ResourceLookupError> {
177 self.world.read_resource()
178 }
179
180 fn write_resource<R: Resource>(
181 &self,
182 ) -> Result<WriteResource<'_, R>, ResourceLookupError> {
183 self.world.write_resource()
184 }
185
186 fn contains_resource<R: Resource>(&self) -> bool {
187 self.world.contains_resource::<R>()
188 }
189}
190
191impl<'w> AccessSpawnEntities for ListenerWorldAccess<'w> {
192 fn spawn_entity(&self) -> EntityBuilder {
193 self.lazy_spawn()
194 }
195}