Skip to main content

pebble/ecs/
events.rs

1use crate::ecs::{
2    resources::{Read, Resources, Write},
3    system_param::SystemParam,
4};
5
6/// Double-buffered event storage, registered via
7/// [`App::add_event`](crate::app::App::add_event). An event sent during
8/// tick `N` is visible to readers for the rest of `N` and all of `N + 1`,
9/// then dropped — so a reader sees it exactly once no matter when it runs
10/// relative to the writer. Read/write it via [`EventReader`]/[`EventWriter`],
11/// not directly.
12pub struct Events<T> {
13    current: Vec<(usize, T)>,
14    previous: Vec<(usize, T)>,
15    next_id: usize,
16}
17
18impl<T> Default for Events<T> {
19    fn default() -> Self {
20        Self { current: Vec::new(), previous: Vec::new(), next_id: 0 }
21    }
22}
23
24impl<T> Events<T> {
25    pub fn send(&mut self, event: T) {
26        self.current.push((self.next_id, event));
27        self.next_id += 1;
28    }
29
30    pub(crate) fn update(&mut self) {
31        self.previous = std::mem::take(&mut self.current);
32    }
33}
34
35/// Reads unread [`Events<T>`] as a system parameter. Each reader keeps its
36/// own cursor (like [`Local`](crate::ecs::local::Local)), so multiple
37/// readers of the same event type don't interfere with each other.
38pub struct EventReader<'a, T: 'static> {
39    events: Read<'a, Events<T>>,
40    last_seen: &'a mut usize,
41}
42
43impl<'a, T: 'static> EventReader<'a, T> {
44    /// Every event sent since this reader last called `iter`, oldest first.
45    pub fn iter(&mut self) -> impl Iterator<Item = &T> + '_ {
46        let seen = *self.last_seen;
47        let unread: Vec<&T> = self
48            .events
49            .previous
50            .iter()
51            .chain(self.events.current.iter())
52            .filter(|(id, _)| *id >= seen)
53            .map(|(_, event)| event)
54            .collect();
55        *self.last_seen = self.events.next_id;
56        unread.into_iter()
57    }
58
59    /// `true` if there's nothing unread for this reader.
60    pub fn is_empty(&self) -> bool {
61        let seen = *self.last_seen;
62        !self.events.previous.iter().chain(self.events.current.iter()).any(|(id, _)| *id >= seen)
63    }
64}
65
66impl<T: 'static> SystemParam for EventReader<'static, T> {
67    type Item<'a> = EventReader<'a, T>;
68    type State = usize;
69
70    fn fetch<'a>(_world: &'a hecs::World, resources: &'a Resources, state: &'a mut Self::State) -> Self::Item<'a> {
71        EventReader { events: Read { inner: resources.get::<Events<T>>() }, last_seen: state }
72    }
73}
74
75impl<T> SystemParam for Option<EventReader<'static, T>>
76where
77    T: 'static + Sync + Send,
78{
79    type Item<'a> = Option<EventReader<'a, T>>;
80    type State = usize;
81
82    fn fetch<'a>(world: &'a hecs::World, resources: &'a Resources, state: &'a mut Self::State) -> Self::Item<'a> {
83        resources.contains::<Events<T>>().then(|| EventReader::fetch(world, resources, state))
84    }
85}
86
87/// Sends into [`Events<T>`] as a system parameter.
88pub struct EventWriter<'a, T: 'static> {
89    events: Write<'a, Events<T>>,
90}
91
92impl<'a, T: 'static> EventWriter<'a, T> {
93    /// Queues `event`, visible to readers for the rest of this tick and all
94    /// of the next.
95    pub fn send(&mut self, event: T) {
96        self.events.send(event);
97    }
98}
99
100impl<T: 'static> SystemParam for EventWriter<'static, T> {
101    type Item<'a> = EventWriter<'a, T>;
102    type State = ();
103
104    fn fetch<'a>(_world: &'a hecs::World, resources: &'a Resources, _state: &'a mut Self::State) -> Self::Item<'a> {
105        EventWriter { events: Write { inner: resources.get_mut::<Events<T>>() } }
106    }
107}
108
109impl<T> SystemParam for Option<EventWriter<'static, T>>
110where
111    T: 'static + Sync + Send,
112{
113    type Item<'a> = Option<EventWriter<'a, T>>;
114    type State = ();
115
116    fn fetch<'a>(world: &'a hecs::World, resources: &'a Resources, state: &'a mut Self::State) -> Self::Item<'a> {
117        resources.contains::<Events<T>>().then(|| EventWriter::fetch(world, resources, state))
118    }
119}
120
121pub(crate) fn age_events<T: Send + Sync + 'static>(mut events: Write<Events<T>>) {
122    events.update();
123}