use crate::system::{AccessInfo, Res, ResMut, SystemParam, SystemParamFetchError};
use crate::world::World;
pub struct Events<T> {
current: Vec<T>,
previous: Vec<T>,
}
impl<T> Events<T> {
pub fn new() -> Self {
Self {
current: Vec::new(),
previous: Vec::new(),
}
}
#[inline]
pub fn send(&mut self, event: T) {
self.current.push(event);
}
#[inline]
pub fn push(&mut self, event: T) {
self.send(event);
}
pub fn update(&mut self) {
self.previous.clear();
std::mem::swap(&mut self.current, &mut self.previous);
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.previous.iter()
}
#[inline]
pub fn len(&self) -> usize {
self.previous.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.previous.is_empty()
}
pub fn clear(&mut self) {
self.current.clear();
self.previous.clear();
}
pub fn drain(&mut self) -> std::vec::IntoIter<T> {
self.previous.drain(..).collect::<Vec<_>>().into_iter()
}
}
impl<T> Default for Events<T> {
fn default() -> Self {
Self::new()
}
}
pub struct EventReader<'w, T: 'static> {
events: Res<'w, Events<T>>,
}
impl<'w, T: 'static> EventReader<'w, T> {
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.events.iter()
}
pub fn len(&self) -> usize {
self.events.len()
}
pub fn is_empty(&self) -> bool {
self.events.is_empty()
}
}
impl<T: 'static> SystemParam for EventReader<'static, T> {
type Item<'w> = EventReader<'w, T>;
fn fetch<'w>(world: &'w World, _dt: f32) -> Result<Self::Item<'w>, SystemParamFetchError> {
let events = Res::<Events<T>>::fetch(world, _dt)?;
Ok(EventReader { events })
}
fn get_access_info(info: &mut AccessInfo) {
Res::<'static, Events<T>>::get_access_info(info);
}
}
pub struct EventWriter<'w, T: 'static> {
events: ResMut<'w, Events<T>>,
}
impl<'w, T: 'static> EventWriter<'w, T> {
pub fn send(&mut self, event: T) {
self.events.send(event);
}
pub fn send_batch(&mut self, events: impl IntoIterator<Item = T>) {
for event in events {
self.events.send(event);
}
}
}
impl<T: 'static> SystemParam for EventWriter<'static, T> {
type Item<'w> = EventWriter<'w, T>;
fn fetch<'w>(world: &'w World, _dt: f32) -> Result<Self::Item<'w>, SystemParamFetchError> {
let events = ResMut::<Events<T>>::fetch(world, _dt)?;
Ok(EventWriter { events })
}
fn get_access_info(info: &mut AccessInfo) {
ResMut::<'static, Events<T>>::get_access_info(info);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_send_and_iter() {
let mut events = Events::new();
events.send(1);
events.send(2);
events.send(3);
assert!(events.iter().next().is_none());
assert!(events.is_empty());
events.update();
let collected: Vec<&i32> = events.iter().collect();
assert_eq!(collected, vec![&1, &2, &3]);
assert_eq!(events.len(), 3);
}
#[test]
fn test_non_destructive_iter() {
let mut events = Events::new();
events.send(42);
events.update();
assert_eq!(events.iter().next(), Some(&42));
assert_eq!(events.iter().next(), Some(&42));
}
#[test]
fn test_double_buffer_isolation() {
let mut events = Events::new();
events.send(1);
events.update();
events.send(2);
let frame1_events: Vec<&i32> = events.iter().collect();
assert_eq!(frame1_events, vec![&1]);
events.update();
let frame2_events: Vec<&i32> = events.iter().collect();
assert_eq!(frame2_events, vec![&2]);
}
#[test]
fn test_update_clears_previous() {
let mut events = Events::new();
events.send(1);
events.update();
assert_eq!(events.len(), 1);
events.update();
assert!(events.is_empty());
assert_eq!(events.len(), 0);
}
#[test]
fn test_push_backward_compat() {
let mut events = Events::new();
events.push(99); events.update();
assert_eq!(events.iter().next(), Some(&99));
}
#[test]
fn test_clear() {
let mut events = Events::new();
events.send(1);
events.update();
events.send(2);
events.clear();
assert!(events.is_empty());
events.update();
assert!(events.is_empty());
}
#[test]
fn test_drain_consumes() {
let mut events = Events::new();
events.send(10);
events.send(20);
events.update();
let drained: Vec<i32> = events.drain().collect();
assert_eq!(drained, vec![10, 20]);
assert!(events.is_empty());
}
#[test]
fn test_no_static_bound() {
struct Ephemeral<'a>(&'a str);
let mut events = Events::new();
let msg = String::from("test");
events.send(Ephemeral(&msg));
events.update();
assert_eq!(events.iter().next().unwrap().0, "test");
}
}