Add a variant of Events::update that returns the removed events (#9542)
# Objective Every frame, `Events::update` gets called, which clears out any old events from the buffer. There should be a way of taking ownership of these old events instead of throwing them away. My use-case is dumping old events into a debug menu so they can be inspected later. One potential workaround is to just have a system that clones any incoming events and stores them in a list -- however, this requires the events to implement `Clone`. ## Solution Add `Events::update_drain`, which returns an iterator of the events that were removed from the buffer.
This commit is contained in:
parent
05b7f60ae5
commit
c440de06f1
@ -228,14 +228,27 @@ impl<E: Event> Events<E> {
|
|||||||
|
|
||||||
/// Swaps the event buffers and clears the oldest event buffer. In general, this should be
|
/// Swaps the event buffers and clears the oldest event buffer. In general, this should be
|
||||||
/// called once per frame/update.
|
/// called once per frame/update.
|
||||||
|
///
|
||||||
|
/// If you need access to the events that were removed, consider using [`Events::update_drain`].
|
||||||
pub fn update(&mut self) {
|
pub fn update(&mut self) {
|
||||||
|
let _ = self.update_drain();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Swaps the event buffers and drains the oldest event buffer, returning an iterator
|
||||||
|
/// of all events that were removed. In general, this should be called once per frame/update.
|
||||||
|
///
|
||||||
|
/// If you do not need to take ownership of the removed events, use [`Events::update`] instead.
|
||||||
|
#[must_use = "If you do not need the returned events, call .update() instead."]
|
||||||
|
pub fn update_drain(&mut self) -> impl Iterator<Item = E> + '_ {
|
||||||
std::mem::swap(&mut self.events_a, &mut self.events_b);
|
std::mem::swap(&mut self.events_a, &mut self.events_b);
|
||||||
self.events_b.clear();
|
let iter = self.events_b.events.drain(..);
|
||||||
self.events_b.start_event_count = self.event_count;
|
self.events_b.start_event_count = self.event_count;
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
self.events_a.start_event_count + self.events_a.len(),
|
self.events_a.start_event_count + self.events_a.len(),
|
||||||
self.events_b.start_event_count
|
self.events_b.start_event_count
|
||||||
);
|
);
|
||||||
|
|
||||||
|
iter.map(|e| e.event)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A system that calls [`Events::update`] once per frame.
|
/// A system that calls [`Events::update`] once per frame.
|
||||||
@ -725,7 +738,7 @@ impl<'a, E: Event> ExactSizeIterator for EventIteratorWithId<'a, E> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{prelude::World, system::SystemState};
|
use crate::system::assert_is_read_only_system;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@ -982,6 +995,31 @@ mod tests {
|
|||||||
assert!(is_empty, "EventReader should be empty");
|
assert!(is_empty, "EventReader should be empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_update_drain() {
|
||||||
|
let mut events = Events::<TestEvent>::default();
|
||||||
|
let mut reader = events.get_reader();
|
||||||
|
|
||||||
|
events.send(TestEvent { i: 0 });
|
||||||
|
events.send(TestEvent { i: 1 });
|
||||||
|
assert_eq!(reader.iter(&events).count(), 2);
|
||||||
|
|
||||||
|
let mut old_events = Vec::from_iter(events.update_drain());
|
||||||
|
assert!(old_events.is_empty());
|
||||||
|
|
||||||
|
events.send(TestEvent { i: 2 });
|
||||||
|
assert_eq!(reader.iter(&events).count(), 1);
|
||||||
|
|
||||||
|
old_events.extend(events.update_drain());
|
||||||
|
assert_eq!(old_events.len(), 2);
|
||||||
|
|
||||||
|
old_events.extend(events.update_drain());
|
||||||
|
assert_eq!(
|
||||||
|
old_events,
|
||||||
|
&[TestEvent { i: 0 }, TestEvent { i: 1 }, TestEvent { i: 2 }]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::iter_nth_zero)]
|
#[allow(clippy::iter_nth_zero)]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_event_iter_nth() {
|
fn test_event_iter_nth() {
|
||||||
@ -1053,13 +1091,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ensure_reader_readonly() {
|
fn ensure_reader_readonly() {
|
||||||
fn read_for<E: Event>() {
|
fn reader_system(_: EventReader<EmptyTestEvent>) {}
|
||||||
let mut world = World::new();
|
|
||||||
world.init_resource::<Events<E>>();
|
assert_is_read_only_system(reader_system);
|
||||||
let mut state = SystemState::<EventReader<E>>::new(&mut world);
|
|
||||||
// This can only work if EventReader only reads the world
|
|
||||||
let _reader = state.get(&world);
|
|
||||||
}
|
|
||||||
read_for::<EmptyTestEvent>();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user