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
	 Joseph
						Joseph