flax/
events.rs

1use alloc::vec::Vec;
2use itertools::Itertools;
3
4use crate::{
5    archetype::{Archetype, Slice, Storage},
6    component::{ComponentDesc, ComponentKey, ComponentValue},
7    filter::StaticFilter,
8    sink::Sink,
9    Component, Entity,
10};
11
12#[derive(Debug, Clone, PartialEq, Eq)]
13/// Represents a single ECS event
14pub struct Event {
15    /// The affected entity
16    pub id: Entity,
17    /// The affected component
18    pub key: ComponentKey,
19    /// The type of event
20    pub kind: EventKind,
21}
22
23impl Event {
24    /// Construct a new event
25    pub fn new(id: Entity, key: ComponentKey, kind: EventKind) -> Self {
26        Self { id, key, kind }
27    }
28
29    /// Construct a modified event
30    pub fn modified(id: Entity, key: ComponentKey) -> Self {
31        Self::new(id, key, EventKind::Modified)
32    }
33
34    /// Construct an added event
35    pub fn added(id: Entity, key: ComponentKey) -> Self {
36        Self::new(id, key, EventKind::Added)
37    }
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
41/// The type of ECS event
42pub enum EventKind {
43    /// The component was added to the entity
44    Added,
45    /// The component was removed from the entity
46    Removed,
47    /// The component was modified
48    Modified,
49}
50
51/// Represents the raw form of an event, where the archetype is available
52pub struct EventData<'a> {
53    /// The affected entities
54    pub ids: &'a [Entity],
55    /// The affected slots
56    pub slots: Slice,
57    /// The affected component
58    pub key: ComponentKey,
59}
60
61/// Allows subscribing to events *inside* the ECS, such as components being added, removed, or
62/// modified.
63///
64/// Most implementations are through the [`Sink`] implementation, which sends a static event for
65/// each entity affected by the event.
66pub trait EventSubscriber: ComponentValue {
67    /// Handle an incoming event
68    fn on_added(&self, storage: &Storage, event: &EventData);
69    /// Handle an incoming event
70    ///
71    /// **Note**: Component storage is inaccessible during this call as it may be called *during*
72    /// itereation or while a query borrow is alive.
73    ///
74    /// Prefer to use this for cache validation and alike, as it *will* be called for intermediate
75    /// events.
76    fn on_modified(&self, event: &EventData);
77    /// Handle an incoming event
78    fn on_removed(&self, storage: &Storage, event: &EventData);
79
80    /// Returns true if the subscriber is still connected
81    fn is_connected(&self) -> bool;
82
83    /// Returns true if the subscriber is interested in this archetype
84    #[inline]
85    fn matches_arch(&self, _: &Archetype) -> bool {
86        true
87    }
88
89    /// Returns true if the subscriber is interested in this component
90    #[inline]
91    fn matches_component(&self, _: ComponentDesc) -> bool {
92        true
93    }
94
95    /// Filter each event before it is generated through a custom function
96    fn filter<F>(self, func: F) -> FilterFunc<Self, F>
97    where
98        Self: Sized,
99        F: Fn(EventKind, &EventData) -> bool,
100    {
101        FilterFunc {
102            subscriber: self,
103            filter: func,
104        }
105    }
106
107    /// Filter the archetypes for which the subscriber will receive events
108    fn filter_arch<F: StaticFilter>(self, filter: F) -> FilterArch<Self, F>
109    where
110        Self: Sized,
111    {
112        FilterArch {
113            filter,
114            subscriber: self,
115        }
116    }
117
118    /// Filter a subscriber to only receive events for a specific set of components
119    fn filter_components<I: IntoIterator<Item = ComponentKey>>(
120        self,
121        components: I,
122    ) -> FilterComponents<Self>
123    where
124        Self: Sized,
125    {
126        FilterComponents {
127            components: components.into_iter().collect(),
128            subscriber: self,
129        }
130    }
131
132    /// Filter a subscriber to only receive events of a specific kind
133    fn filter_event_kind(self, event_kind: EventKind) -> FilterEventKind<Self>
134    where
135        Self: Sized,
136    {
137        FilterEventKind {
138            event_kind,
139            subscriber: self,
140        }
141    }
142}
143
144impl<S> EventSubscriber for S
145where
146    S: 'static + Send + Sync + Sink<Event>,
147{
148    fn on_added(&self, _: &Storage, event: &EventData) {
149        for &id in event.ids {
150            self.send(Event {
151                id,
152                key: event.key,
153                kind: EventKind::Added,
154            });
155        }
156    }
157
158    fn on_modified(&self, event: &EventData) {
159        for &id in event.ids {
160            self.send(Event {
161                id,
162                key: event.key,
163                kind: EventKind::Modified,
164            });
165        }
166    }
167
168    fn on_removed(&self, _: &Storage, event: &EventData) {
169        for &id in event.ids {
170            self.send(Event {
171                id,
172                key: event.key,
173                kind: EventKind::Removed,
174            });
175        }
176    }
177
178    fn is_connected(&self) -> bool {
179        <Self as Sink<Event>>::is_connected(self)
180    }
181}
182
183/// Receive the component value of an event
184///
185/// This is a convenience wrapper around [`EventSubscriber`] that sends the component value along
186///
187/// **Note**: This only tracks addition and removal of components, not modification. This is due to
188/// a limitation with references lifetimes during iteration, as the values can't be accessed by the
189/// subscriber simultaneously.
190pub struct WithValue<T, S> {
191    component: Component<T>,
192    sink: S,
193}
194
195impl<T, S> WithValue<T, S> {
196    /// Create a new `WithValue` subscriber
197    pub fn new(component: Component<T>, sink: S) -> Self {
198        Self { component, sink }
199    }
200}
201
202impl<T: ComponentValue + Clone, S: 'static + Send + Sync + Sink<(Event, T)>> EventSubscriber
203    for WithValue<T, S>
204{
205    fn on_added(&self, storage: &Storage, event: &EventData) {
206        let values = storage.downcast_ref::<T>();
207        for (&id, slot) in event.ids.iter().zip_eq(event.slots.as_range()) {
208            let value = values[slot].clone();
209
210            self.sink.send((
211                Event {
212                    id,
213                    key: event.key,
214                    kind: EventKind::Added,
215                },
216                value,
217            ));
218        }
219    }
220
221    fn on_modified(&self, _: &EventData) {}
222
223    fn on_removed(&self, storage: &Storage, event: &EventData) {
224        let values = storage.downcast_ref::<T>();
225        for (&id, slot) in event.ids.iter().zip_eq(event.slots.as_range()) {
226            let value = values[slot].clone();
227
228            self.sink.send((
229                Event {
230                    id,
231                    key: event.key,
232                    kind: EventKind::Removed,
233                },
234                value,
235            ));
236        }
237    }
238
239    fn is_connected(&self) -> bool {
240        self.sink.is_connected()
241    }
242
243    fn matches_component(&self, desc: ComponentDesc) -> bool {
244        self.component.desc() == desc
245    }
246
247    fn matches_arch(&self, arch: &Archetype) -> bool {
248        arch.has(self.component.key())
249    }
250}
251
252/// Filter the archetypes for which the subscriber will receive events
253pub struct FilterArch<S, F> {
254    filter: F,
255    subscriber: S,
256}
257
258impl<S, F> EventSubscriber for FilterArch<S, F>
259where
260    S: EventSubscriber,
261    F: ComponentValue + StaticFilter,
262{
263    fn on_added(&self, storage: &Storage, event: &EventData) {
264        self.subscriber.on_added(storage, event)
265    }
266
267    fn on_modified(&self, event: &EventData) {
268        self.subscriber.on_modified(event);
269    }
270
271    fn on_removed(&self, storage: &Storage, event: &EventData) {
272        self.subscriber.on_removed(storage, event)
273    }
274
275    #[inline]
276    fn is_connected(&self) -> bool {
277        self.subscriber.is_connected()
278    }
279
280    #[inline]
281    fn matches_arch(&self, arch: &Archetype) -> bool {
282        self.filter.filter_static(arch) && self.subscriber.matches_arch(arch)
283    }
284
285    #[inline]
286    fn matches_component(&self, desc: ComponentDesc) -> bool {
287        self.subscriber.matches_component(desc)
288    }
289}
290
291/// Filter the archetypes for which the subscriber will receive events
292pub struct FilterFunc<S, F> {
293    filter: F,
294    subscriber: S,
295}
296
297impl<S, F> EventSubscriber for FilterFunc<S, F>
298where
299    S: EventSubscriber,
300    F: ComponentValue + Fn(EventKind, &EventData) -> bool,
301{
302    fn on_added(&self, storage: &Storage, event: &EventData) {
303        if (self.filter)(EventKind::Added, event) {
304            self.subscriber.on_added(storage, event)
305        }
306    }
307
308    fn on_modified(&self, event: &EventData) {
309        if (self.filter)(EventKind::Modified, event) {
310            self.subscriber.on_modified(event)
311        }
312    }
313
314    fn on_removed(&self, storage: &Storage, event: &EventData) {
315        if (self.filter)(EventKind::Removed, event) {
316            self.subscriber.on_removed(storage, event)
317        }
318    }
319
320    #[inline]
321    fn matches_arch(&self, arch: &Archetype) -> bool {
322        self.subscriber.matches_arch(arch)
323    }
324
325    #[inline]
326    fn matches_component(&self, desc: ComponentDesc) -> bool {
327        self.subscriber.matches_component(desc)
328    }
329
330    #[inline]
331    fn is_connected(&self) -> bool {
332        self.subscriber.is_connected()
333    }
334}
335
336/// Filter a subscriber to only receive events for a specific set of components
337pub struct FilterComponents<S> {
338    components: Vec<ComponentKey>,
339    subscriber: S,
340}
341
342impl<S> EventSubscriber for FilterComponents<S>
343where
344    S: EventSubscriber,
345{
346    fn on_added(&self, storage: &Storage, event: &EventData) {
347        self.subscriber.on_added(storage, event)
348    }
349
350    fn on_modified(&self, event: &EventData) {
351        self.subscriber.on_modified(event)
352    }
353
354    fn on_removed(&self, storage: &Storage, event: &EventData) {
355        self.subscriber.on_removed(storage, event)
356    }
357
358    #[inline]
359    fn matches_arch(&self, arch: &Archetype) -> bool {
360        self.components.iter().any(|&key| arch.has(key)) && self.subscriber.matches_arch(arch)
361    }
362
363    #[inline]
364    fn matches_component(&self, desc: ComponentDesc) -> bool {
365        self.components.contains(&desc.key()) && self.subscriber.matches_component(desc)
366    }
367
368    #[inline]
369    fn is_connected(&self) -> bool {
370        self.subscriber.is_connected()
371    }
372}
373
374/// Filter a subscriber to only receive events of a specific kind
375pub struct FilterEventKind<S> {
376    event_kind: EventKind,
377    subscriber: S,
378}
379
380impl<S> EventSubscriber for FilterEventKind<S>
381where
382    S: EventSubscriber,
383{
384    fn on_added(&self, storage: &Storage, event: &EventData) {
385        if self.event_kind == EventKind::Added {
386            self.subscriber.on_added(storage, event)
387        }
388    }
389
390    fn on_modified(&self, event: &EventData) {
391        if self.event_kind == EventKind::Modified {
392            self.subscriber.on_modified(event)
393        }
394    }
395
396    fn on_removed(&self, storage: &Storage, event: &EventData) {
397        if self.event_kind == EventKind::Removed {
398            self.subscriber.on_removed(storage, event)
399        }
400    }
401
402    fn is_connected(&self) -> bool {
403        self.subscriber.is_connected()
404    }
405}
406
407/// Maps an event to the associated entity id.
408pub struct WithIds<S> {
409    sink: S,
410}
411
412impl<S> WithIds<S> {
413    /// Create a new entity id sink
414    pub fn new(sink: S) -> Self {
415        Self { sink }
416    }
417}
418
419impl<S: Sink<Entity>> Sink<Event> for WithIds<S> {
420    fn send(&self, event: Event) {
421        self.sink.send(event.id);
422    }
423
424    fn is_connected(&self) -> bool {
425        self.sink.is_connected()
426    }
427}