diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index 7567200a22ba6..cdf1984c8b01e 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -1,7 +1,7 @@ use crate::{CoreStage, Plugin, PluginGroup, PluginGroupBuilder, StartupSchedule, StartupStage}; pub use bevy_derive::AppLabel; use bevy_ecs::{ - event::Events, + event::{Event, Events}, prelude::{FromWorld, IntoExclusiveSystem}, schedule::{ IntoSystemDescriptor, Schedule, ShouldRun, Stage, StageLabel, State, StateData, SystemSet, @@ -622,7 +622,7 @@ impl App { /// ``` pub fn add_event(&mut self) -> &mut Self where - T: Resource, + T: Event, { if !self.world.contains_resource::>() { self.init_resource::>() diff --git a/crates/bevy_ecs/src/event.rs b/crates/bevy_ecs/src/event.rs index 7147a275ddb3f..b28e036c4060c 100644 --- a/crates/bevy_ecs/src/event.rs +++ b/crates/bevy_ecs/src/event.rs @@ -1,7 +1,7 @@ //! Event handling types. +use crate as bevy_ecs; use crate::system::{Local, Res, ResMut, SystemParam}; -use crate::{self as bevy_ecs, system::Resource}; use bevy_utils::tracing::trace; use std::{ fmt::{self}, @@ -9,44 +9,51 @@ use std::{ marker::PhantomData, }; +/// A type that can be stored in an [`Events`] resource +/// You can conveniently access events using the [`EventReader`] and [`EventWriter`] system parameter. +/// +/// Events must be thread-safe. +pub trait Event: Send + Sync + 'static {} +impl Event for T where T: Send + Sync + 'static {} + /// An `EventId` uniquely identifies an event. /// /// An `EventId` can among other things be used to trace the flow of an event from the point it was /// sent to the point it was processed. #[derive(Eq, PartialEq, Ord, PartialOrd, Hash)] -pub struct EventId { +pub struct EventId { pub id: usize, - _marker: PhantomData, + _marker: PhantomData, } -impl Copy for EventId {} -impl Clone for EventId { +impl Copy for EventId {} +impl Clone for EventId { fn clone(&self) -> Self { *self } } -impl fmt::Display for EventId { +impl fmt::Display for EventId { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ::fmt(self, f) } } -impl fmt::Debug for EventId { +impl fmt::Debug for EventId { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "event<{}>#{}", - std::any::type_name::().split("::").last().unwrap(), + std::any::type_name::().split("::").last().unwrap(), self.id, ) } } #[derive(Debug)] -struct EventInstance { - pub event_id: EventId, - pub event: T, +struct EventInstance { + pub event_id: EventId, + pub event: E, } #[derive(Debug)] @@ -127,16 +134,16 @@ enum State { /// [Example usage standalone.](https://github.com/bevyengine/bevy/blob/latest/bevy_ecs/examples/events.rs) /// #[derive(Debug)] -pub struct Events { - events_a: Vec>, - events_b: Vec>, +pub struct Events { + events_a: Vec>, + events_b: Vec>, a_start_event_count: usize, b_start_event_count: usize, event_count: usize, state: State, } -impl Default for Events { +impl Default for Events { fn default() -> Self { Events { a_start_event_count: 0, @@ -149,55 +156,55 @@ impl Default for Events { } } -fn map_instance_event_with_id(event_instance: &EventInstance) -> (&T, EventId) { +fn map_instance_event_with_id(event_instance: &EventInstance) -> (&E, EventId) { (&event_instance.event, event_instance.event_id) } -fn map_instance_event(event_instance: &EventInstance) -> &T { +fn map_instance_event(event_instance: &EventInstance) -> &E { &event_instance.event } /// Reads events of type `T` in order and tracks which events have already been read. #[derive(SystemParam)] -pub struct EventReader<'w, 's, T: Resource> { - last_event_count: Local<'s, (usize, PhantomData)>, - events: Res<'w, Events>, +pub struct EventReader<'w, 's, E: Event> { + last_event_count: Local<'s, (usize, PhantomData)>, + events: Res<'w, Events>, } /// Sends events of type `T`. #[derive(SystemParam)] -pub struct EventWriter<'w, 's, T: Resource> { - events: ResMut<'w, Events>, +pub struct EventWriter<'w, 's, E: Event> { + events: ResMut<'w, Events>, #[system_param(ignore)] marker: PhantomData<&'s usize>, } -impl<'w, 's, T: Resource> EventWriter<'w, 's, T> { +impl<'w, 's, E: Event> EventWriter<'w, 's, E> { /// Sends an `event`. [`EventReader`]s can then read the event. /// See [`Events`] for details. - pub fn send(&mut self, event: T) { + pub fn send(&mut self, event: E) { self.events.send(event); } - pub fn send_batch(&mut self, events: impl Iterator) { + pub fn send_batch(&mut self, events: impl Iterator) { self.events.extend(events); } /// Sends the default value of the event. Useful when the event is an empty struct. pub fn send_default(&mut self) where - T: Default, + E: Default, { self.events.send_default(); } } -pub struct ManualEventReader { +pub struct ManualEventReader { last_event_count: usize, - _marker: PhantomData, + _marker: PhantomData, } -impl Default for ManualEventReader { +impl Default for ManualEventReader { fn default() -> Self { ManualEventReader { last_event_count: 0, @@ -207,37 +214,42 @@ impl Default for ManualEventReader { } #[allow(clippy::len_without_is_empty)] // Check fails since the is_empty implementation has a signature other than `(&self) -> bool` -impl ManualEventReader { +impl ManualEventReader { /// See [`EventReader::iter`] - pub fn iter<'a>(&'a mut self, events: &'a Events) -> impl DoubleEndedIterator { + pub fn iter<'a>( + &'a mut self, + events: &'a Events, + ) -> impl DoubleEndedIterator + ExactSizeIterator { internal_event_reader(&mut self.last_event_count, events).map(|(e, _)| e) } /// See [`EventReader::iter_with_id`] pub fn iter_with_id<'a>( &'a mut self, - events: &'a Events, - ) -> impl DoubleEndedIterator)> { + events: &'a Events, + ) -> impl DoubleEndedIterator)> + + ExactSizeIterator)> { 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) + pub fn len(&self, events: &Events) -> usize { + internal_event_reader(&mut self.last_event_count.clone(), events).len() } /// See [`EventReader::is_empty`] - pub fn is_empty(&self, events: &Events) -> bool { + 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 /// messages. -fn internal_event_reader<'a, T>( +fn internal_event_reader<'a, E: Event>( last_event_count: &'a mut usize, - events: &'a Events, -) -> impl DoubleEndedIterator)> { + events: &'a Events, +) -> impl DoubleEndedIterator)> + ExactSizeIterator)> +{ // if the reader has seen some of the events in a buffer, find the proper index offset. // otherwise read all events in the buffer let a_index = if *last_event_count > events.a_start_event_count { @@ -260,19 +272,77 @@ fn internal_event_reader<'a, T>( }; iterator .map(map_instance_event_with_id) + .with_exact_size(unread_count) .inspect(move |(_, id)| *last_event_count = (id.id + 1).max(*last_event_count)) } -impl<'w, 's, T: Resource> EventReader<'w, 's, T> { +trait IteratorExt { + fn with_exact_size(self, len: usize) -> ExactSize + where + Self: Sized, + { + ExactSize::new(self, len) + } +} +impl IteratorExt for I where I: Iterator {} + +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[derive(Clone)] +struct ExactSize { + iter: I, + len: usize, +} +impl ExactSize { + fn new(iter: I, len: usize) -> Self { + ExactSize { iter, len } + } +} + +impl Iterator for ExactSize { + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + self.iter.next().map(|e| { + self.len -= 1; + e + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (self.len, Some(self.len)) + } +} + +impl DoubleEndedIterator for ExactSize { + #[inline] + fn next_back(&mut self) -> Option { + self.iter.next_back().map(|e| { + self.len -= 1; + e + }) + } +} +impl ExactSizeIterator for ExactSize { + fn len(&self) -> usize { + self.len + } +} + +impl<'w, 's, E: Event> EventReader<'w, 's, E> { /// Iterates over the events this [`EventReader`] has not seen yet. This updates the /// [`EventReader`]'s event counter, which means subsequent event reads will not include events /// that happened before now. - pub fn iter(&mut self) -> impl DoubleEndedIterator { + pub fn iter(&mut self) -> impl DoubleEndedIterator + ExactSizeIterator { self.iter_with_id().map(|(event, _id)| event) } /// Like [`iter`](Self::iter), except also returning the [`EventId`] of the events. - pub fn iter_with_id(&mut self) -> impl DoubleEndedIterator)> { + pub fn iter_with_id( + &mut self, + ) -> impl DoubleEndedIterator)> + ExactSizeIterator)> + { internal_event_reader(&mut self.last_event_count.0, &self.events).map(|(event, id)| { trace!("EventReader::iter() -> {}", id); (event, id) @@ -281,7 +351,7 @@ impl<'w, 's, T: Resource> EventReader<'w, 's, T> { /// 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) + internal_event_reader(&mut self.last_event_count.0.clone(), &self.events).len() } /// Determines if are any events available to be read without consuming any. @@ -290,10 +360,10 @@ impl<'w, 's, T: Resource> EventReader<'w, 's, T> { } } -impl Events { +impl Events { /// "Sends" an `event` by writing it to the current event buffer. [`EventReader`]s can then read /// the event. - pub fn send(&mut self, event: T) { + pub fn send(&mut self, event: E) { let event_id = EventId { id: self.event_count, _marker: PhantomData, @@ -313,13 +383,13 @@ impl Events { /// Sends the default value of the event. Useful when the event is an empty struct. pub fn send_default(&mut self) where - T: Default, + E: Default, { self.send(Default::default()); } /// Gets a new [`ManualEventReader`]. This will include all events already in the event buffers. - pub fn get_reader(&self) -> ManualEventReader { + pub fn get_reader(&self) -> ManualEventReader { ManualEventReader { last_event_count: 0, _marker: PhantomData, @@ -328,7 +398,7 @@ impl Events { /// Gets a new [`ManualEventReader`]. This will ignore all events already in the event buffers. /// It will read all future events. - pub fn get_reader_current(&self) -> ManualEventReader { + pub fn get_reader_current(&self) -> ManualEventReader { ManualEventReader { last_event_count: self.event_count, _marker: PhantomData, @@ -378,10 +448,10 @@ impl Events { } /// Creates a draining iterator that removes all events. - pub fn drain(&mut self) -> impl Iterator + '_ { + pub fn drain(&mut self) -> impl Iterator + '_ { self.reset_start_event_count(); - let map = |i: EventInstance| i.event; + let map = |i: EventInstance| i.event; match self.state { State::A => self .events_b @@ -402,41 +472,20 @@ impl 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. - pub fn iter_current_update_events(&self) -> impl DoubleEndedIterator { + pub fn iter_current_update_events( + &self, + ) -> impl DoubleEndedIterator + ExactSizeIterator { match self.state { State::A => self.events_a.iter().map(map_instance_event), 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 { +impl std::iter::Extend for Events { fn extend(&mut self, iter: I) where - I: IntoIterator, + I: IntoIterator, { let mut event_count = self.event_count; let events = iter.into_iter().map(|event| { @@ -562,11 +611,11 @@ mod tests { ); } - fn get_events( - events: &Events, - reader: &mut ManualEventReader, - ) -> Vec { - reader.iter(events).cloned().collect::>() + fn get_events( + events: &Events, + reader: &mut ManualEventReader, + ) -> Vec { + reader.iter(events).cloned().collect::>() } #[derive(PartialEq, Eq, Debug)] @@ -648,6 +697,21 @@ mod tests { assert!(!events.get_reader().is_empty(&events)); } + #[test] + fn test_event_iter_len_updated() { + let mut events = Events::::default(); + events.send(TestEvent { i: 0 }); + events.send(TestEvent { i: 1 }); + events.send(TestEvent { i: 2 }); + let mut reader = events.get_reader(); + let mut iter = reader.iter(&events); + assert_eq!(iter.len(), 3); + iter.next(); + assert_eq!(iter.len(), 2); + iter.next_back(); + assert_eq!(iter.len(), 1); + } + #[test] fn test_event_reader_len_current() { let mut events = Events::::default();