// ============================================================
// Ordered event queue
//
// EventBus is ideal for one-shot flags. EventQueue preserves multiplicity and
// order, which is needed by input processing, damage notifications, and agent
// message delivery.
// ============================================================
///|
/// One ordered event with an optional typed payload.
pub struct EventRecord {
id : Int
name : String
payload : Value?
}
///|
/// Create an event record.
pub fn EventRecord::new(
id : Int,
name : String,
payload : Value?,
) -> EventRecord {
{ id, name, payload }
}
///|
/// Event sequence number.
pub fn EventRecord::id(self : EventRecord) -> Int {
self.id
}
///|
/// Event name.
pub fn EventRecord::name(self : EventRecord) -> String {
self.name
}
///|
/// Optional payload.
pub fn EventRecord::payload(self : EventRecord) -> Value? {
self.payload
}
///|
/// FIFO event queue.
pub struct EventQueue {
items : Array[EventRecord]
next_id : Ref[Int]
}
///|
/// Create an empty queue.
pub fn EventQueue::new() -> EventQueue {
{ items: [], next_id: Ref::new(1) }
}
///|
/// Append an event without a payload.
pub fn EventQueue::emit(self : EventQueue, name : String) -> Int {
let id = self.next_id.get()
self.next_id.set(id + 1)
self.items.push(EventRecord::new(id, name, None))
id
}
///|
/// Append an event with a payload.
pub fn EventQueue::emit_value(
self : EventQueue,
name : String,
payload : Value,
) -> Int {
let id = self.next_id.get()
self.next_id.set(id + 1)
self.items.push(EventRecord::new(id, name, Some(payload)))
id
}
///|
/// Number of pending events.
pub fn EventQueue::size(self : EventQueue) -> Int {
self.items.length()
}
///|
/// Whether at least one event with this name is pending.
pub fn EventQueue::contains(self : EventQueue, name : String) -> Bool {
for event in self.items {
if event.name == name {
return true
}
}
false
}
///|
/// Remove and return the first event, if any.
pub fn EventQueue::poll(self : EventQueue) -> EventRecord? {
if self.items.length() == 0 {
None
} else {
let event = self.items[0]
let _ = self.items.remove(0)
Some(event)
}
}
///|
/// Remove and return the first matching event.
pub fn EventQueue::poll_name(self : EventQueue, name : String) -> EventRecord? {
let mut i = 0
while i < self.items.length() {
if self.items[i].name == name {
let event = self.items[i]
let _ = self.items.remove(i)
return Some(event)
}
i = i + 1
}
None
}
///|
/// Copy pending events in FIFO order without consuming them.
pub fn EventQueue::pending(self : EventQueue) -> Array[EventRecord] {
let copy : Array[EventRecord] = []
for event in self.items {
copy.push(event)
}
copy
}
///|
/// Remove every pending event and return the removed records.
pub fn EventQueue::drain(self : EventQueue) -> Array[EventRecord] {
let result = self.pending()
self.items.clear()
result
}
///|
/// Discard pending events but preserve monotonically increasing IDs.
pub fn EventQueue::clear(self : EventQueue) -> Unit {
self.items.clear()
}