bevy/crates/bevy_ecs/src/event/mutator.rs
Clar Fon efda7f3f9c
Simpler lint fixes: makes ci lints work but disables a lint for now (#15376)
Takes the first two commits from #15375 and adds suggestions from this
comment:
https://github.com/bevyengine/bevy/pull/15375#issuecomment-2366968300

See #15375 for more reasoning/motivation.

## Rebasing (rerunning)

```rust
git switch simpler-lint-fixes
git reset --hard main
cargo fmt --all -- --unstable-features --config normalize_comments=true,imports_granularity=Crate
cargo fmt --all
git add --update
git commit --message "rustfmt"
cargo clippy --workspace --all-targets --all-features --fix
cargo fmt --all -- --unstable-features --config normalize_comments=true,imports_granularity=Crate
cargo fmt --all
git add --update
git commit --message "clippy"
git cherry-pick e6c0b94f6795222310fb812fa5c4512661fc7887
```
2024-09-24 11:42:59 +00:00

144 lines
5.1 KiB
Rust

use crate as bevy_ecs;
#[cfg(feature = "multi_threaded")]
use bevy_ecs::event::EventMutParIter;
use bevy_ecs::{
event::{Event, EventCursor, EventMutIterator, EventMutIteratorWithId, Events},
system::{Local, ResMut, SystemParam},
};
/// Mutably reads events of type `T` keeping track of which events have already been read
/// by each system allowing multiple systems to read the same events. Ideal for chains of systems
/// that all want to modify the same events.
///
/// # Usage
///
/// `EventMutators`s are usually declared as a [`SystemParam`].
/// ```
/// # use bevy_ecs::prelude::*;
///
/// #[derive(Event, Debug)]
/// pub struct MyEvent(pub u32); // Custom event type.
/// fn my_system(mut reader: EventMutator<MyEvent>) {
/// for event in reader.read() {
/// event.0 += 1;
/// println!("received event: {:?}", event);
/// }
/// }
/// ```
///
/// # Concurrency
///
/// Multiple systems with `EventMutator<T>` of the same event type can not run concurrently.
/// They also can not be executed in parallel with [`EventReader`] or [`EventWriter`].
///
/// # Clearing, Reading, and Peeking
///
/// Events are stored in a double buffered queue that switches each frame. This switch also clears the previous
/// frame's events. Events should be read each frame otherwise they may be lost. For manual control over this
/// behavior, see [`Events`].
///
/// Most of the time systems will want to use [`EventMutator::read()`]. This function creates an iterator over
/// all events that haven't been read yet by this system, marking the event as read in the process.
///
/// [`EventReader`]: super::EventReader
/// [`EventWriter`]: super::EventWriter
#[derive(SystemParam, Debug)]
pub struct EventMutator<'w, 's, E: Event> {
pub(super) reader: Local<'s, EventCursor<E>>,
events: ResMut<'w, Events<E>>,
}
impl<'w, 's, E: Event> EventMutator<'w, 's, E> {
/// Iterates over the events this [`EventMutator`] has not seen yet. This updates the
/// [`EventMutator`]'s event counter, which means subsequent event reads will not include events
/// that happened before now.
pub fn read(&mut self) -> EventMutIterator<'_, E> {
self.reader.read_mut(&mut self.events)
}
/// Like [`read`](Self::read), except also returning the [`EventId`](super::EventId) of the events.
pub fn read_with_id(&mut self) -> EventMutIteratorWithId<'_, E> {
self.reader.read_mut_with_id(&mut self.events)
}
/// Returns a parallel iterator over the events this [`EventMutator`] has not seen yet.
/// See also [`for_each`](super::EventParIter::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: EventMutator<MyEvent>, counter: Res<Counter>| {
/// events.par_read().for_each(|MyEvent { value }| {
/// counter.0.fetch_add(*value, Ordering::Relaxed);
/// });
/// });
/// for value in 0..100 {
/// world.send_event(MyEvent { value });
/// }
/// schedule.run(&mut world);
/// let Counter(counter) = world.remove_resource::<Counter>().unwrap();
/// // all events were processed
/// assert_eq!(counter.into_inner(), 4950);
/// ```
#[cfg(feature = "multi_threaded")]
pub fn par_read(&mut self) -> EventMutParIter<'_, E> {
self.reader.par_read_mut(&mut 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)
}
/// Returns `true` if there are no events available to read.
///
/// # Example
///
/// The following example shows a useful pattern where some behavior is triggered if new events are available.
/// [`EventMutator::clear()`] is used so the same events don't re-trigger the behavior the next time the system runs.
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// #[derive(Event)]
/// struct CollisionEvent;
///
/// fn play_collision_sound(mut events: EventMutator<CollisionEvent>) {
/// if !events.is_empty() {
/// events.clear();
/// // Play a sound
/// }
/// }
/// # bevy_ecs::system::assert_is_system(play_collision_sound);
/// ```
pub fn is_empty(&self) -> bool {
self.reader.is_empty(&self.events)
}
/// Consumes all available events.
///
/// This means these events will not appear in calls to [`EventMutator::read()`] or
/// [`EventMutator::read_with_id()`] and [`EventMutator::is_empty()`] will return `true`.
///
/// For usage, see [`EventMutator::is_empty()`].
pub fn clear(&mut self) {
self.reader.clear(&self.events);
}
}