Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add trivial Event trait #4685

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 73 additions & 65 deletions crates/bevy_ecs/src/event.rs
Original file line number Diff line number Diff line change
@@ -1,52 +1,58 @@
//! Event handling types.

use crate::system::{Local, Res, ResMut, SystemParam};
use crate::{self as bevy_ecs, system::Resource};
// Required for the SystemParam derive macro to work
use crate::{self as bevy_ecs};
use bevy_utils::tracing::trace;
use std::{
fmt::{self},
hash::Hash,
marker::PhantomData,
};
use std::{fmt, hash::Hash, marker::PhantomData};

/// An `EventId` uniquely identifies an event.
/// A type that can be stored in an [`Events<E>`] resource
///
/// An `EventId` can among other things be used to trace the flow of an event from the point it was
/// You can conveniently access events using the [`EventReader`] and [`EventWriter`] system parameter.
///
/// Events must be thread-safe.
pub trait Event: Send + Sync + 'static {}

impl<E: Send + Sync + 'static> Event for E {}

/// Uniquely identifies an event.
///
/// Among other things, this can 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<T> {
pub struct EventId<E: Event> {
pub id: usize,
_marker: PhantomData<T>,
_marker: PhantomData<E>,
}

impl<T> Copy for EventId<T> {}
impl<T> Clone for EventId<T> {
impl<E: Event> Copy for EventId<E> {}
impl<E: Event> Clone for EventId<E> {
fn clone(&self) -> Self {
*self
}
}

impl<T> fmt::Display for EventId<T> {
impl<E: Event> fmt::Display for EventId<E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
<Self as fmt::Debug>::fmt(self, f)
}
}

impl<T> fmt::Debug for EventId<T> {
impl<E: Event> fmt::Debug for EventId<E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"event<{}>#{}",
std::any::type_name::<T>().split("::").last().unwrap(),
std::any::type_name::<E>().split("::").last().unwrap(),
self.id,
)
}
}

#[derive(Debug)]
struct EventInstance<T> {
pub event_id: EventId<T>,
pub event: T,
struct EventInstance<E: Event> {
pub event_id: EventId<E>,
pub event: E,
}

#[derive(Debug)]
Expand All @@ -57,6 +63,8 @@ enum State {

/// An event collection that represents the events that occurred within the last two
/// [`Events::update`] calls.
///
/// Only types which implement the [`Event`] trait can be stored as events.
/// Events can be written to using an [`EventWriter`]
/// and are typically cheaply read using an [`EventReader`].
///
Expand Down Expand Up @@ -127,16 +135,16 @@ enum State {
/// [Example usage standalone.](https://github.com/bevyengine/bevy/blob/latest/bevy_ecs/examples/events.rs)
///
#[derive(Debug)]
pub struct Events<T> {
events_a: Vec<EventInstance<T>>,
events_b: Vec<EventInstance<T>>,
pub struct Events<E: Event> {
events_a: Vec<EventInstance<E>>,
events_b: Vec<EventInstance<E>>,
a_start_event_count: usize,
b_start_event_count: usize,
event_count: usize,
state: State,
}

impl<T> Default for Events<T> {
impl<E: Event> Default for Events<E> {
fn default() -> Self {
Events {
a_start_event_count: 0,
Expand All @@ -149,55 +157,55 @@ impl<T> Default for Events<T> {
}
}

fn map_instance_event_with_id<T>(event_instance: &EventInstance<T>) -> (&T, EventId<T>) {
fn map_instance_event_with_id<E: Event>(event_instance: &EventInstance<E>) -> (&E, EventId<E>) {
(&event_instance.event, event_instance.event_id)
}

fn map_instance_event<T>(event_instance: &EventInstance<T>) -> &T {
fn map_instance_event<E: Event>(event_instance: &EventInstance<E>) -> &E {
&event_instance.event
}

/// Reads events of type `T` in order and tracks which events have already been read.
/// Reads events of type `E` 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<T>)>,
events: Res<'w, Events<T>>,
pub struct EventReader<'w, 's, E: Event> {
last_event_count: Local<'s, (usize, PhantomData<E>)>,
events: Res<'w, Events<E>>,
}

/// Sends events of type `T`.
/// Sends events of type `E`.
#[derive(SystemParam)]
pub struct EventWriter<'w, 's, T: Resource> {
events: ResMut<'w, Events<T>>,
pub struct EventWriter<'w, 's, E: Event> {
events: ResMut<'w, Events<E>>,
#[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<Item = T>) {
pub fn send_batch(&mut self, events: impl Iterator<Item = E>) {
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<T> {
pub struct ManualEventReader<E> {
last_event_count: usize,
_marker: PhantomData<T>,
_marker: PhantomData<E>,
}

impl<T> Default for ManualEventReader<T> {
impl<E> Default for ManualEventReader<E> {
fn default() -> Self {
ManualEventReader {
last_event_count: 0,
Expand All @@ -207,37 +215,37 @@ impl<T> Default for ManualEventReader<T> {
}

#[allow(clippy::len_without_is_empty)] // Check fails since the is_empty implementation has a signature other than `(&self) -> bool`
impl<T: Resource> ManualEventReader<T> {
impl<E: Event> ManualEventReader<E> {
/// See [`EventReader::iter`]
pub fn iter<'a>(&'a mut self, events: &'a Events<T>) -> impl DoubleEndedIterator<Item = &'a T> {
pub fn iter<'a>(&'a mut self, events: &'a Events<E>) -> impl DoubleEndedIterator<Item = &'a E> {
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<T>,
) -> impl DoubleEndedIterator<Item = (&'a T, EventId<T>)> {
events: &'a Events<E>,
) -> impl DoubleEndedIterator<Item = (&'a E, EventId<E>)> {
internal_event_reader(&mut self.last_event_count, events)
}

/// See [`EventReader::len`]
pub fn len(&self, events: &Events<T>) -> usize {
pub fn len(&self, events: &Events<E>) -> usize {
events.event_reader_len(self.last_event_count)
}

/// See [`EventReader::is_empty`]
pub fn is_empty(&self, events: &Events<T>) -> bool {
pub fn is_empty(&self, events: &Events<E>) -> 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<T>,
) -> impl DoubleEndedIterator<Item = (&'a T, EventId<T>)> {
events: &'a Events<E>,
) -> impl DoubleEndedIterator<Item = (&'a E, EventId<E>)> {
// 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 {
Expand All @@ -263,16 +271,16 @@ fn internal_event_reader<'a, T>(
.inspect(move |(_, id)| *last_event_count = (id.id + 1).max(*last_event_count))
}

impl<'w, 's, T: Resource> EventReader<'w, 's, T> {
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<Item = &T> {
pub fn iter(&mut self) -> impl DoubleEndedIterator<Item = &E> {
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<Item = (&T, EventId<T>)> {
pub fn iter_with_id(&mut self) -> impl DoubleEndedIterator<Item = (&E, EventId<E>)> {
internal_event_reader(&mut self.last_event_count.0, &self.events).map(|(event, id)| {
trace!("EventReader::iter() -> {}", id);
(event, id)
Expand All @@ -290,10 +298,10 @@ impl<'w, 's, T: Resource> EventReader<'w, 's, T> {
}
}

impl<T: Resource> Events<T> {
impl<E: Event> Events<E> {
/// "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,
Expand All @@ -313,13 +321,13 @@ impl<T: Resource> Events<T> {
/// 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<T> {
pub fn get_reader(&self) -> ManualEventReader<E> {
ManualEventReader {
last_event_count: 0,
_marker: PhantomData,
Expand All @@ -328,7 +336,7 @@ impl<T: Resource> Events<T> {

/// 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<T> {
pub fn get_reader_current(&self) -> ManualEventReader<E> {
ManualEventReader {
last_event_count: self.event_count,
_marker: PhantomData,
Expand Down Expand Up @@ -378,10 +386,10 @@ impl<T: Resource> Events<T> {
}

/// Creates a draining iterator that removes all events.
pub fn drain(&mut self) -> impl Iterator<Item = T> + '_ {
pub fn drain(&mut self) -> impl Iterator<Item = E> + '_ {
self.reset_start_event_count();

let map = |i: EventInstance<T>| i.event;
let map = |i: EventInstance<E>| i.event;
match self.state {
State::A => self
.events_b
Expand All @@ -402,7 +410,7 @@ impl<T: Resource> Events<T> {
/// 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<Item = &T> {
pub fn iter_current_update_events(&self) -> impl DoubleEndedIterator<Item = &E> {
match self.state {
State::A => self.events_a.iter().map(map_instance_event),
State::B => self.events_b.iter().map(map_instance_event),
Expand Down Expand Up @@ -433,10 +441,10 @@ impl<T: Resource> Events<T> {
}
}

impl<T> std::iter::Extend<T> for Events<T> {
impl<E: Event> std::iter::Extend<E> for Events<E> {
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = T>,
I: IntoIterator<Item = E>,
{
let mut event_count = self.event_count;
let events = iter.into_iter().map(|event| {
Expand Down Expand Up @@ -562,11 +570,11 @@ mod tests {
);
}

fn get_events<T: Resource + Clone>(
events: &Events<T>,
reader: &mut ManualEventReader<T>,
) -> Vec<T> {
reader.iter(events).cloned().collect::<Vec<T>>()
fn get_events<E: Event + Clone>(
events: &Events<E>,
reader: &mut ManualEventReader<E>,
) -> Vec<E> {
reader.iter(events).cloned().collect::<Vec<E>>()
}

#[derive(PartialEq, Eq, Debug)]
Expand Down