diff --git a/crates/bevy_ecs/src/event.rs b/crates/bevy_ecs/src/event.rs index cf6c92c7b67ad..a7e5d1b319c34 100644 --- a/crates/bevy_ecs/src/event.rs +++ b/crates/bevy_ecs/src/event.rs @@ -192,7 +192,8 @@ impl Default for ManualEventReader { } } -impl ManualEventReader { +#[allow(clippy::len_without_is_empty)] // Check fails since the is_empty implementation has a signature other than `(&self) -> bool` +impl ManualEventReader { /// See [`EventReader::iter`] pub fn iter<'a>(&'a mut self, events: &'a Events) -> impl DoubleEndedIterator { internal_event_reader(&mut self.last_event_count, events).map(|(e, _)| e) @@ -205,6 +206,16 @@ impl ManualEventReader { ) -> impl DoubleEndedIterator)> { internal_event_reader(&mut self.last_event_count, events) } + + /// See [`EventReader::len`] + pub fn len(&self, events: &Events) -> usize { + events.event_reader_len(self.last_event_count) + } + + /// See [`EventReader::is_empty`] + pub fn is_empty(&self, events: &Events) -> bool { + self.len(events) == 0 + } } /// Like [`iter_with_id`](EventReader::iter_with_id) except not emitting any traces for read @@ -253,6 +264,16 @@ impl<'w, 's, T: Resource> EventReader<'w, 's, T> { (event, id) }) } + + /// Determines the number of events available to be read from this [`EventReader`] without consuming any. + pub fn len(&self) -> usize { + self.events.event_reader_len(self.last_event_count.0) + } + + /// Determines if are any events available to be read without consuming any. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } } impl Events { @@ -355,7 +376,7 @@ impl Events { /// Iterates over events that happened since the last "update" call. /// WARNING: You probably don't want to use this call. In most cases you should use an - /// `EventReader`. You should only use this if you know you only need to consume events + /// [`EventReader`]. You should only use this if you know you only need to consume events /// between the last `update()` call and your call to `iter_current_update_events`. /// If events happen outside that window, they will not be handled. For example, any events that /// happen after this call and before the next `update()` call will be dropped. @@ -365,6 +386,29 @@ impl Events { State::B => self.events_b.iter().map(map_instance_event), } } + + /// Determines how many events are in the reader after the given `last_event_count` parameter + fn event_reader_len(&self, last_event_count: usize) -> usize { + let a_count = if last_event_count <= self.a_start_event_count { + self.events_a.len() + } else { + self.events_a + .len() + .checked_sub(last_event_count - self.a_start_event_count) + .unwrap_or_default() + }; + + let b_count = if last_event_count <= self.b_start_event_count { + self.events_b.len() + } else { + self.events_b + .len() + .checked_sub(last_event_count - self.b_start_event_count) + .unwrap_or_default() + }; + + a_count + b_count + } } impl std::iter::Extend for Events { @@ -566,4 +610,46 @@ mod tests { events.update(); assert!(events.is_empty()); } + + #[test] + fn test_event_reader_len_empty() { + let events = Events::::default(); + assert_eq!(events.get_reader().len(&events), 0); + assert!(events.get_reader().is_empty(&events)); + } + + #[test] + fn test_event_reader_len_filled() { + let mut events = Events::::default(); + events.send(TestEvent { i: 0 }); + assert_eq!(events.get_reader().len(&events), 1); + assert!(!events.get_reader().is_empty(&events)); + } + + #[test] + fn test_event_reader_len_current() { + let mut events = Events::::default(); + events.send(TestEvent { i: 0 }); + let reader = events.get_reader_current(); + assert!(reader.is_empty(&events)); + events.send(TestEvent { i: 0 }); + assert_eq!(reader.len(&events), 1); + assert!(!reader.is_empty(&events)); + } + + #[test] + fn test_event_reader_len_update() { + let mut events = Events::::default(); + events.send(TestEvent { i: 0 }); + events.send(TestEvent { i: 0 }); + let reader = events.get_reader(); + assert_eq!(reader.len(&events), 2); + events.update(); + events.send(TestEvent { i: 0 }); + assert_eq!(reader.len(&events), 3); + events.update(); + assert_eq!(reader.len(&events), 1); + events.update(); + assert!(reader.is_empty(&events)); + } }