Skip to content

Commit

Permalink
Added peeking to EventMutator
Browse files Browse the repository at this point in the history
  • Loading branch information
BobG1983 committed Jul 5, 2024
1 parent f414749 commit 437f7c1
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 6 deletions.
65 changes: 63 additions & 2 deletions crates/bevy_ecs/src/event/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -802,7 +802,7 @@ mod tests {
}

#[test]
fn test_event_mutator_iter_last() {
fn test_event_mutator_read_iter_last() {
use bevy_ecs::prelude::*;

let mut world = World::new();
Expand Down Expand Up @@ -831,6 +831,40 @@ mod tests {
assert!(last.is_none(), "EventMutator should be empty");
}

#[test]
fn test_event_mutator_peek_iter_last() {
use bevy_ecs::prelude::*;

let mut world = World::new();
world.init_resource::<Events<TestEvent>>();

let mut peeker =
IntoSystem::into_system(|events: EventMutator<TestEvent>| -> Option<TestEvent> {
events.peek().last().copied()
});
peeker.initialize(&mut world);

let last = peeker.run((), &mut world);
assert!(last.is_none(), "EventMutator should be empty");

world.send_event(TestEvent { i: 0 });
let last = peeker.run((), &mut world);
assert_eq!(last, Some(TestEvent { i: 0 }));

world.send_event(TestEvent { i: 1 });
world.send_event(TestEvent { i: 2 });
world.send_event(TestEvent { i: 3 });
let last = peeker.run((), &mut world);
assert_eq!(last, Some(TestEvent { i: 3 }));

let last = peeker.run((), &mut world);
assert_eq!(
last,
Some(TestEvent { i: 3 }),
"EventMutator should not be empty"
);
}

#[allow(clippy::iter_nth_zero)]
#[test]
fn test_event_reader_read_iter_nth() {
Expand Down Expand Up @@ -887,7 +921,7 @@ mod tests {

#[allow(clippy::iter_nth_zero)]
#[test]
fn test_event_mutator_iter_nth() {
fn test_event_mutator_read_iter_nth() {
use bevy_ecs::prelude::*;

let mut world = World::new();
Expand All @@ -911,4 +945,31 @@ mod tests {
});
schedule.run(&mut world);
}

#[allow(clippy::iter_nth_zero)]
#[test]
fn test_event_mutator_peek_iter_nth() {
use bevy_ecs::prelude::*;

let mut world = World::new();
world.init_resource::<Events<TestEvent>>();

world.send_event(TestEvent { i: 0 });
world.send_event(TestEvent { i: 1 });
world.send_event(TestEvent { i: 2 });
world.send_event(TestEvent { i: 3 });
world.send_event(TestEvent { i: 4 });

let mut schedule = Schedule::default();
schedule.add_systems(|events: EventMutator<TestEvent>| {
let mut iter = events.peek();

assert_eq!(iter.next(), Some(&TestEvent { i: 0 }));
assert_eq!(iter.nth(2), Some(&TestEvent { i: 3 }));
assert_eq!(iter.nth(1), None);

assert!(!events.is_empty());
});
schedule.run(&mut world);
}
}
64 changes: 62 additions & 2 deletions crates/bevy_ecs/src/event/mutator.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use crate as bevy_ecs;
#[cfg(feature = "multi_threaded")]
use bevy_ecs::event::EventMutParIter;
use bevy_ecs::event::{EventMutParIter, EventPeekParIter};
use bevy_ecs::{
event::{Event, EventCursor, EventMutIterator, EventMutIteratorWithId, Events},
event::{
Event, EventCursor, EventMutIterator, EventMutIteratorWithId, EventPeekIterator,
EventPeekIteratorWithId, Events,
},
system::{Local, ResMut, SystemParam},
};

Expand Down Expand Up @@ -54,11 +57,24 @@ impl<'w, 's, E: Event> EventMutator<'w, 's, E> {
self.reader.read_mut(&mut self.events)
}

/// Iterates over all the events this [`EventMutator`] currently has, including those that have
/// been read (see [`EventMutator::read()`],[`EventMutator::read_with_id()`], [`EventMutator::par_read`]).
/// Unlike [`read`](Self::read), this does not update the [`EventMutator`]'s event counter and
/// thus does not mark the event as read.
pub fn peek(&self) -> EventPeekIterator<'_, E> {
self.reader.peek(&self.events)
}

/// Like [`read`](Self::read), except also returning the [`EventId`] of the events.
pub fn read_with_id(&mut self) -> EventMutIteratorWithId<'_, E> {
self.reader.read_mut_with_id(&mut self.events)
}

/// Like [`peek`](Self::peek), except also returning the [`EventId`] of the events.
pub fn peek_with_id(&self) -> EventPeekIteratorWithId<'_, E> {
self.reader.peek_with_id(&self.events)
}

/// Returns a parallel iterator over the events this [`EventMutator`] has not seen yet.
/// See also [`for_each`](EventParIter::for_each).
///
Expand Down Expand Up @@ -100,6 +116,50 @@ impl<'w, 's, E: Event> EventMutator<'w, 's, E> {
self.reader.par_read_mut(&mut self.events)
}

/// Returns a parallel iterator over the events this [`EventReader`] has not read yet.
/// Unlike [`par_read`](Self::par_read) this does not update the [`EventReader`]'s
/// event counter and thus does not mark the event as read.
///
/// For more information on this see ['peek'](Self::read) and [`for_each`](EventRefParIter::for_each).
///
/// # Example
/// ```
/// # use bevy_ecs::prelude::*;
/// # use std::sync::atomic::{AtomicUsize, Ordering};
///
/// #[derive(Event)]
/// struct MyEvent {
/// value: usize,
/// }
///
/// #[derive(Resource, Default)]
/// struct Counter(AtomicUsize);
///
/// // setup
/// let mut world = World::new();
/// world.init_resource::<Events<MyEvent>>();
/// world.insert_resource(Counter::default());
///
/// let mut schedule = Schedule::default();
/// schedule.add_systems(|mut events: EventReader<MyEvent>, counter: Res<Counter>| {
/// events.par_peek().for_each(|MyEvent { value }| {
/// counter.0.fetch_add(*value, Ordering::Relaxed);
/// });
/// });
/// for _ in 0..100 {
/// world.send_event(MyEvent { value: 1 });
/// }
/// schedule.run(&mut world);
/// let Counter(counter) = world.remove_resource::<Counter>().unwrap();
/// // all events were processed
/// assert_eq!(counter.into_inner(), 100);
/// ```
///
#[cfg(feature = "multi_threaded")]
pub fn par_peek(&self) -> EventPeekParIter<'_, E> {
self.reader.par_peek(&self.events)
}

/// Determines the number of events available to be read from this [`EventMutator`] without consuming any.
pub fn len(&self) -> usize {
self.reader.len(&self.events)
Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_ecs/src/event/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ impl<'w, 's, E: Event> EventReader<'w, 's, E> {
self.reader.read(&self.events)
}

/// Iterates over the events this [`EventReader`] has read
/// (see [`EventReader::read()`],[`EventReader::read_with_id()`], [`EventReader::par_read`]).
/// Iterates over all the events this [`EventReader`] currently has, including those that have
/// been read (see [`EventReader::read()`],[`EventReader::read_with_id()`], [`EventReader::par_read`]).
/// Unlike [`read`](Self::read), this does not update the [`EventReader`]'s event counter and
/// thus does not mark the event as read.
pub fn peek(&self) -> EventPeekIterator<'_, E> {
Expand Down

0 comments on commit 437f7c1

Please sign in to comment.