diff --git a/crates/bevy_ecs/src/event.rs b/crates/bevy_ecs/src/event.rs index 22af1b3ed2dff..bb85742f5b372 100644 --- a/crates/bevy_ecs/src/event.rs +++ b/crates/bevy_ecs/src/event.rs @@ -57,6 +57,42 @@ struct EventInstance { pub event: E, } +/// Settings for controlling the general behavior of [`Events`]. +pub struct EventSettings { + /// Controls how and when the memory allocated for events will be freed + pub garbage_collection: EventGarbageCollection, + marker_: PhantomData T>, +} + +impl Default for EventSettings { + fn default() -> Self { + Self { + garbage_collection: Default::default(), + marker_: PhantomData, + } + } +} + +/// Settings for controlling the garbage collection behavior of [`Events`]. +pub enum EventGarbageCollection { + /// Exponentially decays the amount of allocated memory for the backing event buffer + /// with a configured minimum. This is the default. + ExponentialFalloff { + /// Each internal vec never goes below this value. + /// There are two internal vecs, so the total minimum capacity is 2 * min_capacity. + /// This defaults to 0. + min_capacity: usize, + }, + /// Disables garbage collection entirely. + None, +} + +impl Default for EventGarbageCollection { + fn default() -> Self { + Self::ExponentialFalloff { min_capacity: 0 } + } +} + /// An event collection that represents the events that occurred within the last two /// [`Events::update`] calls. /// Events can be written to using an [`EventWriter`] @@ -82,7 +118,7 @@ struct EventInstance { /// /// # Example /// ``` -/// use bevy_ecs::event::Events; +/// use bevy_ecs::event::*; /// /// struct MyEvent { /// value: usize @@ -91,9 +127,10 @@ struct EventInstance { /// // setup /// let mut events = Events::::default(); /// let mut reader = events.get_reader(); +/// let settings = EventSettings::::default(); /// /// // run this once per update/frame -/// events.update(); +/// events.update(&settings); /// /// // somewhere else: send an event /// events.send(MyEvent { value: 1 }); @@ -437,9 +474,19 @@ impl Events { /// Swaps the event buffers and clears the oldest event buffer. In general, this should be /// called once per frame/update. - pub fn update(&mut self) { + pub fn update(&mut self, settings: &EventSettings) { std::mem::swap(&mut self.events_a, &mut self.events_b); + // Garbage collect unused event space. Shrink after clear to avoid a copy. + let new_capacity = match settings.garbage_collection { + EventGarbageCollection::ExponentialFalloff { min_capacity } => self + .events_b + .len() + .max(self.events_b.capacity() / 2) + .max(min_capacity), + EventGarbageCollection::None => self.events_b.capacity(), + }; self.events_b.clear(); + self.events_b.shrink_to(new_capacity); self.events_b.start_event_count = self.event_count; debug_assert_eq!( self.events_a.start_event_count + self.events_a.len(), @@ -448,8 +495,12 @@ impl Events { } /// A system that calls [`Events::update`] once per frame. - pub fn update_system(mut events: ResMut) { - events.update(); + pub fn update_system(mut events: ResMut, settings: Option>>) { + if let Some(settings) = settings { + events.update(&settings); + } else { + events.update(&Default::default()); + } } #[inline] @@ -598,7 +649,7 @@ mod tests { "reader_a receives next unread event" ); - events.update(); + events.update(&Default::default()); let mut reader_d = events.get_reader(); @@ -620,7 +671,7 @@ mod tests { "reader_d receives all events created before and after update" ); - events.update(); + events.update(&Default::default()); assert_eq!( get_events(&events, &mut reader_missed), @@ -654,7 +705,7 @@ mod tests { assert!(reader.iter(&events).next().is_none()); events.send(E(2)); - events.update(); + events.update(&Default::default()); events.send(E(3)); assert!(reader.iter(&events).eq([E(2), E(3)].iter())); @@ -691,12 +742,12 @@ mod tests { events.send(TestEvent { i: 0 }); assert!(!events.is_empty()); - events.update(); + events.update(&Default::default()); assert!(!events.is_empty()); // events are only empty after the second call to update // due to double buffering. - events.update(); + events.update(&Default::default()); assert!(events.is_empty()); } @@ -750,12 +801,12 @@ mod tests { events.send(TestEvent { i: 0 }); let reader = events.get_reader(); assert_eq!(reader.len(&events), 2); - events.update(); + events.update(&Default::default()); events.send(TestEvent { i: 0 }); assert_eq!(reader.len(&events), 3); - events.update(); + events.update(&Default::default()); assert_eq!(reader.len(&events), 1); - events.update(); + events.update(&Default::default()); assert!(reader.is_empty(&events)); }