Skip to main content

goud_engine/core/event/
resource.rs

1//! ECS resource wrapper for the event system.
2
3use crate::core::event::{
4    queue::EventQueue, reader::EventReader, traits::Event, writer::EventWriter,
5};
6
7/// ECS-compatible resource wrapper for event queues.
8///
9/// `Events<E>` wraps an [`EventQueue<E>`] and provides a high-level API
10/// suitable for use as an ECS resource. It manages the event lifecycle
11/// automatically and provides convenient accessor methods.
12///
13/// # Resource Integration
14///
15/// In a typical ECS architecture, `Events<E>` is stored as a resource in the
16/// World. Systems that need to send or receive events request it via the
17/// resource system.
18///
19/// # Frame Lifecycle
20///
21/// The `update()` method must be called once per frame (typically at the start
22/// or end of the frame) to:
23/// 1. Swap the double buffers
24/// 2. Clear stale events from the previous frame
25///
26/// This ensures events persist for exactly one frame after being sent.
27///
28/// # Example
29///
30/// ```rust
31/// use goud_engine::core::event::Events;
32///
33/// #[derive(Debug, Clone)]
34/// struct DamageEvent {
35///     entity_id: u32,
36///     amount: i32,
37/// }
38///
39/// // Create the events resource
40/// let mut events: Events<DamageEvent> = Events::new();
41///
42/// // Systems can send events
43/// events.send(DamageEvent { entity_id: 1, amount: 50 });
44/// events.send(DamageEvent { entity_id: 2, amount: 25 });
45///
46/// // At frame boundary, call update
47/// events.update();
48///
49/// // Now systems can read the events
50/// let mut reader = events.reader();
51/// for event in reader.read() {
52///     println!("Entity {} took {} damage", event.entity_id, event.amount);
53/// }
54/// ```
55///
56/// # Thread Safety
57///
58/// `Events<E>` is `Send + Sync` when `E` is `Send + Sync`, enabling safe
59/// use in multi-threaded ECS systems.
60pub struct Events<E: Event> {
61    /// The underlying double-buffered event queue
62    queue: EventQueue<E>,
63}
64
65impl<E: Event> Events<E> {
66    /// Creates a new empty `Events` resource.
67    ///
68    /// # Example
69    ///
70    /// ```rust
71    /// use goud_engine::core::event::Events;
72    ///
73    /// struct MyEvent { data: i32 }
74    /// let events: Events<MyEvent> = Events::new();
75    /// ```
76    #[must_use]
77    pub fn new() -> Self {
78        Self {
79            queue: EventQueue::new(),
80        }
81    }
82
83    /// Creates an `EventReader` for reading events from this resource.
84    ///
85    /// Multiple readers can be created simultaneously, as they only require
86    /// shared access to the underlying queue.
87    ///
88    /// # Example
89    ///
90    /// ```rust
91    /// use goud_engine::core::event::Events;
92    ///
93    /// #[derive(Debug)]
94    /// struct MyEvent { id: u32 }
95    ///
96    /// let mut events: Events<MyEvent> = Events::new();
97    /// events.send(MyEvent { id: 1 });
98    /// events.update();
99    ///
100    /// let mut reader = events.reader();
101    /// for event in reader.read() {
102    ///     println!("Got event: {:?}", event);
103    /// }
104    /// ```
105    #[must_use]
106    pub fn reader(&self) -> EventReader<'_, E> {
107        EventReader::new(&self.queue)
108    }
109
110    /// Creates an `EventWriter` for sending events to this resource.
111    ///
112    /// Only one writer can exist at a time due to the mutable borrow requirement.
113    ///
114    /// # Example
115    ///
116    /// ```rust
117    /// use goud_engine::core::event::Events;
118    ///
119    /// struct SpawnEvent { entity_type: String }
120    ///
121    /// let mut events: Events<SpawnEvent> = Events::new();
122    ///
123    /// {
124    ///     let mut writer = events.writer();
125    ///     writer.send(SpawnEvent { entity_type: "enemy".to_string() });
126    ///     writer.send(SpawnEvent { entity_type: "item".to_string() });
127    /// }
128    /// ```
129    #[must_use]
130    pub fn writer(&mut self) -> EventWriter<'_, E> {
131        EventWriter::new(&mut self.queue)
132    }
133
134    /// Sends an event directly to the write buffer.
135    ///
136    /// This is a convenience method equivalent to creating a writer and
137    /// calling `send()` on it.
138    ///
139    /// # Example
140    ///
141    /// ```rust
142    /// use goud_engine::core::event::Events;
143    ///
144    /// struct InputEvent { key: char }
145    ///
146    /// let mut events: Events<InputEvent> = Events::new();
147    /// events.send(InputEvent { key: 'w' });
148    /// events.send(InputEvent { key: 'a' });
149    /// ```
150    pub fn send(&mut self, event: E) {
151        self.queue.send(event);
152    }
153
154    /// Sends multiple events to the write buffer in batch.
155    ///
156    /// More efficient than calling `send()` multiple times when you have
157    /// a collection of events.
158    ///
159    /// # Example
160    ///
161    /// ```rust
162    /// use goud_engine::core::event::Events;
163    ///
164    /// #[derive(Clone)]
165    /// struct ParticleEvent { x: f32, y: f32 }
166    ///
167    /// let mut events: Events<ParticleEvent> = Events::new();
168    /// let particles = vec![
169    ///     ParticleEvent { x: 0.0, y: 0.0 },
170    ///     ParticleEvent { x: 1.0, y: 1.0 },
171    ///     ParticleEvent { x: 2.0, y: 2.0 },
172    /// ];
173    /// events.send_batch(particles);
174    /// ```
175    pub fn send_batch(&mut self, events: impl IntoIterator<Item = E>) {
176        for event in events {
177            self.queue.send(event);
178        }
179    }
180
181    /// Updates the event system at frame boundary.
182    ///
183    /// This method MUST be called exactly once per frame, typically at the
184    /// start or end of the game loop. It:
185    /// 1. Clears events from the previous read buffer (they've had their chance)
186    /// 2. Swaps the buffers so newly written events become readable
187    ///
188    /// # Frame Timing
189    ///
190    /// ```text
191    /// Frame N:
192    ///   1. update() called - events from Frame N-1 become readable
193    ///   2. Systems read events
194    ///   3. Systems write new events
195    ///
196    /// Frame N+1:
197    ///   1. update() called - Frame N-1 events cleared, Frame N events readable
198    ///   ... and so on
199    /// ```
200    ///
201    /// # Important
202    ///
203    /// - Calling `update()` more than once per frame will cause events to be
204    ///   lost (the write buffer gets swapped to read before systems can write)
205    /// - Not calling `update()` will cause events to accumulate and never
206    ///   become readable
207    ///
208    /// # Example
209    ///
210    /// ```rust
211    /// use goud_engine::core::event::Events;
212    ///
213    /// struct GameEvent;
214    ///
215    /// let mut events: Events<GameEvent> = Events::new();
216    ///
217    /// // Game loop
218    /// for frame in 0..3 {
219    ///     // Start of frame: update events
220    ///     events.update();
221    ///
222    ///     // Read events from previous frame
223    ///     let mut reader = events.reader();
224    ///     for _ in reader.read() {
225    ///         // Process events...
226    ///     }
227    ///
228    ///     // Systems write new events
229    ///     events.send(GameEvent);
230    /// }
231    /// ```
232    pub fn update(&mut self) {
233        self.queue.swap_buffers();
234    }
235
236    /// Drains all events from the read buffer, consuming them.
237    ///
238    /// Unlike using a reader, this removes the events entirely from the buffer.
239    ///
240    /// # Example
241    ///
242    /// ```rust
243    /// use goud_engine::core::event::Events;
244    ///
245    /// struct Event { id: u32 }
246    ///
247    /// let mut events: Events<Event> = Events::new();
248    /// events.send(Event { id: 1 });
249    /// events.send(Event { id: 2 });
250    /// events.update();
251    ///
252    /// let collected: Vec<Event> = events.drain().collect();
253    /// assert_eq!(collected.len(), 2);
254    /// ```
255    pub fn drain(&mut self) -> impl Iterator<Item = E> + '_ {
256        self.queue.drain()
257    }
258
259    /// Clears all events from both buffers.
260    ///
261    /// Use this when transitioning between game states or when you need
262    /// to discard all pending events.
263    ///
264    /// # Example
265    ///
266    /// ```rust
267    /// use goud_engine::core::event::Events;
268    ///
269    /// struct Event;
270    ///
271    /// let mut events: Events<Event> = Events::new();
272    /// events.send(Event);
273    /// events.update();
274    /// events.send(Event);
275    ///
276    /// events.clear();
277    /// assert!(events.is_empty());
278    /// ```
279    pub fn clear(&mut self) {
280        self.queue.clear();
281    }
282
283    /// Returns `true` if no events are pending in the write buffer.
284    ///
285    /// Note: The read buffer may still contain events from the previous frame.
286    ///
287    /// # Example
288    ///
289    /// ```rust
290    /// use goud_engine::core::event::Events;
291    ///
292    /// struct Event;
293    ///
294    /// let mut events: Events<Event> = Events::new();
295    /// assert!(events.is_empty());
296    ///
297    /// events.send(Event);
298    /// assert!(!events.is_empty());
299    /// ```
300    #[must_use]
301    pub fn is_empty(&self) -> bool {
302        self.queue.is_empty()
303    }
304
305    /// Returns the number of events in the write buffer.
306    ///
307    /// # Example
308    ///
309    /// ```rust
310    /// use goud_engine::core::event::Events;
311    ///
312    /// struct Event;
313    ///
314    /// let mut events: Events<Event> = Events::new();
315    /// events.send(Event);
316    /// events.send(Event);
317    ///
318    /// assert_eq!(events.len(), 2);
319    /// ```
320    #[must_use]
321    pub fn len(&self) -> usize {
322        self.queue.len()
323    }
324
325    /// Returns the number of events available for reading.
326    ///
327    /// # Example
328    ///
329    /// ```rust
330    /// use goud_engine::core::event::Events;
331    ///
332    /// struct Event;
333    ///
334    /// let mut events: Events<Event> = Events::new();
335    /// events.send(Event);
336    /// events.send(Event);
337    ///
338    /// // Events are in write buffer
339    /// assert_eq!(events.read_len(), 0);
340    ///
341    /// events.update();
342    ///
343    /// // Now in read buffer
344    /// assert_eq!(events.read_len(), 2);
345    /// ```
346    #[must_use]
347    pub fn read_len(&self) -> usize {
348        self.queue.read_len()
349    }
350
351    /// Returns a slice of events available for reading.
352    ///
353    /// This provides direct access to the read buffer, enabling cursor-based
354    /// reading patterns used by ECS system parameters.
355    ///
356    /// # Example
357    ///
358    /// ```rust
359    /// use goud_engine::core::event::Events;
360    ///
361    /// struct Event { id: u32 }
362    ///
363    /// let mut events: Events<Event> = Events::new();
364    /// events.send(Event { id: 1 });
365    /// events.send(Event { id: 2 });
366    /// events.update();
367    ///
368    /// let buffer = events.read_buffer();
369    /// assert_eq!(buffer.len(), 2);
370    /// ```
371    #[must_use]
372    pub fn read_buffer(&self) -> &[E] {
373        self.queue.read_buffer()
374    }
375}
376
377impl<E: Event> Default for Events<E> {
378    fn default() -> Self {
379        Self::new()
380    }
381}
382
383// Note: Events<E> is automatically Send + Sync because EventQueue<E> is Send + Sync
384// when E is Send + Sync, which is guaranteed by the Event trait bound.
385// This is enforced by the test `test_events_is_send_sync`.