Skip to main content

kvas_engine/
events.rs

1//! Typed, bounded event queues for gameplay code.
2//!
3//! These queues are ordinary owned data: keep them in host-owned systems or in
4//! an individual script. They do not register global resources and are not a
5//! cross-library message bus. Events are consumed explicitly, never by the clock.
6//!
7//! ```
8//! use kvas_engine::events::EventQueue;
9//! let mut events = EventQueue::new(2);
10//! assert!(events.push("door opened").is_ok());
11//! assert_eq!(events.drain().collect::<Vec<_>>(), vec!["door opened"]);
12//! assert!(events.is_empty());
13//! ```
14use std::collections::VecDeque;
15
16/// FIFO queue with an explicit capacity limit and no silent event loss.
17#[derive(Clone, Debug)]
18pub struct EventQueue<T> {
19    events: VecDeque<T>,
20    capacity: usize,
21}
22
23impl<T> Default for EventQueue<T> {
24    /// Creates a queue allowing up to 256 events.
25    fn default() -> Self {
26        Self::new(256)
27    }
28}
29
30impl<T> EventQueue<T> {
31    /// Creates an empty bounded queue. A zero limit rejects every event.
32    /// Memory is allocated on demand, not up front for the full limit.
33    pub fn new(capacity: usize) -> Self {
34        Self { events: VecDeque::new(), capacity }
35    }
36    /// Pushes to the back or returns the original event if the queue is full.
37    pub fn push(&mut self, event: T) -> Result<(), T> {
38        if self.events.len() >= self.capacity {
39            return Err(event);
40        }
41        self.events.push_back(event);
42        Ok(())
43    }
44    /// Pops the oldest pending event, if any.
45    pub fn pop(&mut self) -> Option<T> {
46        self.events.pop_front()
47    }
48    /// Borrows the oldest pending event without consuming it.
49    pub fn front(&self) -> Option<&T> {
50        self.events.front()
51    }
52    /// Borrows all pending events in insertion order.
53    pub fn iter(&self) -> impl DoubleEndedIterator<Item = &T> + ExactSizeIterator {
54        self.events.iter()
55    }
56    /// Consumes all queued events in insertion order.
57    /// Dropping the drain early also removes the remaining events.
58    pub fn drain(&mut self) -> std::collections::vec_deque::Drain<'_, T> {
59        self.events.drain(..)
60    }
61    /// Discards every event, retaining allocated memory.
62    pub fn clear(&mut self) {
63        self.events.clear();
64    }
65    /// Current pending count.
66    pub fn len(&self) -> usize {
67        self.events.len()
68    }
69    /// Whether the queue contains no pending events.
70    pub fn is_empty(&self) -> bool {
71        self.events.is_empty()
72    }
73    /// Whether another push would fail.
74    pub fn is_full(&self) -> bool {
75        self.len() >= self.capacity
76    }
77    /// Maximum pending count, independent of allocated storage size.
78    pub fn capacity(&self) -> usize {
79        self.capacity
80    }
81    /// Free logical slots before reaching the limit.
82    pub fn remaining_capacity(&self) -> usize {
83        self.capacity - self.len()
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90    #[test]
91    fn fifo_overflow_returns_ownership_and_drain_clears() {
92        let mut q = EventQueue::new(2);
93        q.push(String::from("a")).unwrap();
94        q.push(String::from("b")).unwrap();
95        assert_eq!(q.push(String::from("c")), Err(String::from("c")));
96        assert!(q.is_full());
97        assert_eq!(q.pop().as_deref(), Some("a"));
98        q.push(String::from("c")).unwrap();
99        assert_eq!(q.iter().map(String::as_str).collect::<Vec<_>>(), vec!["b", "c"]);
100        {
101            let mut drain = q.drain();
102            assert_eq!(drain.next().as_deref(), Some("b"));
103        }
104        assert!(q.is_empty());
105        assert_eq!(q.remaining_capacity(), 2);
106        assert_eq!(EventQueue::new(0).push(7), Err(7));
107    }
108}