bevy/crates/bevy_ecs/src/event/mod.rs
Zachary Harrold d70595b667
Add core and alloc over std Lints (#15281)
# Objective

- Fixes #6370
- Closes #6581

## Solution

- Added the following lints to the workspace:
  - `std_instead_of_core`
  - `std_instead_of_alloc`
  - `alloc_instead_of_core`
- Used `cargo +nightly fmt` with [item level use
formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Item%5C%3A)
to split all `use` statements into single items.
- Used `cargo clippy --workspace --all-targets --all-features --fix
--allow-dirty` to _attempt_ to resolve the new linting issues, and
intervened where the lint was unable to resolve the issue automatically
(usually due to needing an `extern crate alloc;` statement in a crate
root).
- Manually removed certain uses of `std` where negative feature gating
prevented `--all-features` from finding the offending uses.
- Used `cargo +nightly fmt` with [crate level use
formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Crate%5C%3A)
to re-merge all `use` statements matching Bevy's previous styling.
- Manually fixed cases where the `fmt` tool could not re-merge `use`
statements due to conditional compilation attributes.

## Testing

- Ran CI locally

## Migration Guide

The MSRV is now 1.81. Please update to this version or higher.

## Notes

- This is a _massive_ change to try and push through, which is why I've
outlined the semi-automatic steps I used to create this PR, in case this
fails and someone else tries again in the future.
- Making this change has no impact on user code, but does mean Bevy
contributors will be warned to use `core` and `alloc` instead of `std`
where possible.
- This lint is a critical first step towards investigating `no_std`
options for Bevy.

---------

Co-authored-by: François Mockers <francois.mockers@vleue.com>
2024-09-27 00:59:59 +00:00

625 lines
20 KiB
Rust

//! Event handling types.
mod base;
mod collections;
mod event_cursor;
mod iterators;
mod mut_iterators;
mod mutator;
mod reader;
mod registry;
mod send_event;
mod update;
mod writer;
pub(crate) use base::EventInstance;
pub use base::{Event, EventId};
pub use bevy_ecs_macros::Event;
pub use collections::{Events, SendBatchIds};
pub use event_cursor::EventCursor;
#[cfg(feature = "multi_threaded")]
pub use iterators::EventParIter;
pub use iterators::{EventIterator, EventIteratorWithId};
#[cfg(feature = "multi_threaded")]
pub use mut_iterators::EventMutParIter;
pub use mut_iterators::{EventMutIterator, EventMutIteratorWithId};
pub use mutator::EventMutator;
pub use reader::EventReader;
pub use registry::{EventRegistry, ShouldUpdateEvents};
pub use send_event::SendEvent;
pub use update::{
event_update_condition, event_update_system, signal_event_update_system, EventUpdates,
};
pub use writer::EventWriter;
#[cfg(test)]
mod tests {
use crate as bevy_ecs;
use bevy_ecs::{event::*, system::assert_is_read_only_system};
use bevy_ecs_macros::Event;
#[derive(Event, Copy, Clone, PartialEq, Eq, Debug)]
struct TestEvent {
i: usize,
}
#[derive(Event, Clone, PartialEq, Debug, Default)]
struct EmptyTestEvent;
fn get_events<E: Event + Clone>(events: &Events<E>, cursor: &mut EventCursor<E>) -> Vec<E> {
cursor.read(events).cloned().collect::<Vec<E>>()
}
#[test]
fn test_events() {
let mut events = Events::<TestEvent>::default();
let event_0 = TestEvent { i: 0 };
let event_1 = TestEvent { i: 1 };
let event_2 = TestEvent { i: 2 };
// this reader will miss event_0 and event_1 because it wont read them over the course of
// two updates
let mut reader_missed: EventCursor<TestEvent> = events.get_cursor();
let mut reader_a: EventCursor<TestEvent> = events.get_cursor();
events.send(event_0);
assert_eq!(
get_events(&events, &mut reader_a),
vec![event_0],
"reader_a created before event receives event"
);
assert_eq!(
get_events(&events, &mut reader_a),
vec![],
"second iteration of reader_a created before event results in zero events"
);
let mut reader_b: EventCursor<TestEvent> = events.get_cursor();
assert_eq!(
get_events(&events, &mut reader_b),
vec![event_0],
"reader_b created after event receives event"
);
assert_eq!(
get_events(&events, &mut reader_b),
vec![],
"second iteration of reader_b created after event results in zero events"
);
events.send(event_1);
let mut reader_c = events.get_cursor();
assert_eq!(
get_events(&events, &mut reader_c),
vec![event_0, event_1],
"reader_c created after two events receives both events"
);
assert_eq!(
get_events(&events, &mut reader_c),
vec![],
"second iteration of reader_c created after two event results in zero events"
);
assert_eq!(
get_events(&events, &mut reader_a),
vec![event_1],
"reader_a receives next unread event"
);
events.update();
let mut reader_d = events.get_cursor();
events.send(event_2);
assert_eq!(
get_events(&events, &mut reader_a),
vec![event_2],
"reader_a receives event created after update"
);
assert_eq!(
get_events(&events, &mut reader_b),
vec![event_1, event_2],
"reader_b receives events created before and after update"
);
assert_eq!(
get_events(&events, &mut reader_d),
vec![event_0, event_1, event_2],
"reader_d receives all events created before and after update"
);
events.update();
assert_eq!(
get_events(&events, &mut reader_missed),
vec![event_2],
"reader_missed missed events unread after two update() calls"
);
}
// Events Collection
fn events_clear_and_read_impl(clear_func: impl FnOnce(&mut Events<TestEvent>)) {
let mut events = Events::<TestEvent>::default();
let mut reader = events.get_cursor();
assert!(reader.read(&events).next().is_none());
events.send(TestEvent { i: 0 });
assert_eq!(*reader.read(&events).next().unwrap(), TestEvent { i: 0 });
assert_eq!(reader.read(&events).next(), None);
events.send(TestEvent { i: 1 });
clear_func(&mut events);
assert!(reader.read(&events).next().is_none());
events.send(TestEvent { i: 2 });
events.update();
events.send(TestEvent { i: 3 });
assert!(reader
.read(&events)
.eq([TestEvent { i: 2 }, TestEvent { i: 3 }].iter()));
}
#[test]
fn test_events_clear_and_read() {
events_clear_and_read_impl(Events::clear);
}
#[test]
fn test_events_drain_and_read() {
events_clear_and_read_impl(|events| {
assert!(events
.drain()
.eq(vec![TestEvent { i: 0 }, TestEvent { i: 1 }].into_iter()));
});
}
#[test]
fn test_events_send_default() {
let mut events = Events::<EmptyTestEvent>::default();
events.send_default();
let mut reader = events.get_cursor();
assert_eq!(get_events(&events, &mut reader), vec![EmptyTestEvent]);
}
#[test]
fn test_send_events_ids() {
let mut events = Events::<TestEvent>::default();
let event_0 = TestEvent { i: 0 };
let event_1 = TestEvent { i: 1 };
let event_2 = TestEvent { i: 2 };
let event_0_id = events.send(event_0);
assert_eq!(
events.get_event(event_0_id.id),
Some((&event_0, event_0_id)),
"Getting a sent event by ID should return the original event"
);
let mut event_ids = events.send_batch([event_1, event_2]);
let event_id = event_ids.next().expect("Event 1 must have been sent");
assert_eq!(
events.get_event(event_id.id),
Some((&event_1, event_id)),
"Getting a sent event by ID should return the original event"
);
let event_id = event_ids.next().expect("Event 2 must have been sent");
assert_eq!(
events.get_event(event_id.id),
Some((&event_2, event_id)),
"Getting a sent event by ID should return the original event"
);
assert!(
event_ids.next().is_none(),
"Only sent two events; got more than two IDs"
);
}
#[test]
fn test_event_registry_can_add_and_remove_events_to_world() {
use bevy_ecs::prelude::*;
let mut world = World::new();
EventRegistry::register_event::<TestEvent>(&mut world);
let has_events = world.get_resource::<Events<TestEvent>>().is_some();
assert!(has_events, "Should have the events resource");
EventRegistry::deregister_events::<TestEvent>(&mut world);
let has_events = world.get_resource::<Events<TestEvent>>().is_some();
assert!(!has_events, "Should not have the events resource");
}
#[test]
fn test_events_update_drain() {
let mut events = Events::<TestEvent>::default();
let mut reader = events.get_cursor();
events.send(TestEvent { i: 0 });
events.send(TestEvent { i: 1 });
assert_eq!(reader.read(&events).count(), 2);
let mut old_events = Vec::from_iter(events.update_drain());
assert!(old_events.is_empty());
events.send(TestEvent { i: 2 });
assert_eq!(reader.read(&events).count(), 1);
old_events.extend(events.update_drain());
assert_eq!(old_events.len(), 2);
old_events.extend(events.update_drain());
assert_eq!(
old_events,
&[TestEvent { i: 0 }, TestEvent { i: 1 }, TestEvent { i: 2 }]
);
}
#[test]
fn test_events_empty() {
let mut events = Events::<TestEvent>::default();
assert!(events.is_empty());
events.send(TestEvent { i: 0 });
assert!(!events.is_empty());
events.update();
assert!(!events.is_empty());
// events are only empty after the second call to update
// due to double buffering.
events.update();
assert!(events.is_empty());
}
#[test]
fn test_events_extend_impl() {
let mut events = Events::<TestEvent>::default();
let mut reader = events.get_cursor();
events.extend(vec![TestEvent { i: 0 }, TestEvent { i: 1 }]);
assert!(reader
.read(&events)
.eq([TestEvent { i: 0 }, TestEvent { i: 1 }].iter()));
}
// Cursor
#[test]
fn test_event_cursor_read() {
let mut events = Events::<TestEvent>::default();
let mut cursor = events.get_cursor();
assert!(cursor.read(&events).next().is_none());
events.send(TestEvent { i: 0 });
let sent_event = cursor.read(&events).next().unwrap();
assert_eq!(sent_event, &TestEvent { i: 0 });
assert!(cursor.read(&events).next().is_none());
events.send(TestEvent { i: 2 });
let sent_event = cursor.read(&events).next().unwrap();
assert_eq!(sent_event, &TestEvent { i: 2 });
assert!(cursor.read(&events).next().is_none());
events.clear();
assert!(cursor.read(&events).next().is_none());
}
#[test]
fn test_event_cursor_read_mut() {
let mut events = Events::<TestEvent>::default();
let mut write_cursor = events.get_cursor();
let mut read_cursor = events.get_cursor();
assert!(write_cursor.read_mut(&mut events).next().is_none());
assert!(read_cursor.read(&events).next().is_none());
events.send(TestEvent { i: 0 });
let sent_event = write_cursor.read_mut(&mut events).next().unwrap();
assert_eq!(sent_event, &mut TestEvent { i: 0 });
*sent_event = TestEvent { i: 1 }; // Mutate whole event
assert_eq!(
read_cursor.read(&events).next().unwrap(),
&TestEvent { i: 1 }
);
assert!(read_cursor.read(&events).next().is_none());
events.send(TestEvent { i: 2 });
let sent_event = write_cursor.read_mut(&mut events).next().unwrap();
assert_eq!(sent_event, &mut TestEvent { i: 2 });
sent_event.i = 3; // Mutate sub value
assert_eq!(
read_cursor.read(&events).next().unwrap(),
&TestEvent { i: 3 }
);
assert!(read_cursor.read(&events).next().is_none());
events.clear();
assert!(write_cursor.read(&events).next().is_none());
assert!(read_cursor.read(&events).next().is_none());
}
#[test]
fn test_event_cursor_clear() {
let mut events = Events::<TestEvent>::default();
let mut reader = events.get_cursor();
events.send(TestEvent { i: 0 });
assert_eq!(reader.len(&events), 1);
reader.clear(&events);
assert_eq!(reader.len(&events), 0);
}
#[test]
fn test_event_cursor_len_update() {
let mut events = Events::<TestEvent>::default();
events.send(TestEvent { i: 0 });
events.send(TestEvent { i: 0 });
let reader = events.get_cursor();
assert_eq!(reader.len(&events), 2);
events.update();
events.send(TestEvent { i: 0 });
assert_eq!(reader.len(&events), 3);
events.update();
assert_eq!(reader.len(&events), 1);
events.update();
assert!(reader.is_empty(&events));
}
#[test]
fn test_event_cursor_len_current() {
let mut events = Events::<TestEvent>::default();
events.send(TestEvent { i: 0 });
let reader = events.get_cursor_current();
assert!(reader.is_empty(&events));
events.send(TestEvent { i: 0 });
assert_eq!(reader.len(&events), 1);
assert!(!reader.is_empty(&events));
}
#[test]
fn test_event_cursor_iter_len_updated() {
let mut events = Events::<TestEvent>::default();
events.send(TestEvent { i: 0 });
events.send(TestEvent { i: 1 });
events.send(TestEvent { i: 2 });
let mut reader = events.get_cursor();
let mut iter = reader.read(&events);
assert_eq!(iter.len(), 3);
iter.next();
assert_eq!(iter.len(), 2);
iter.next();
assert_eq!(iter.len(), 1);
iter.next();
assert_eq!(iter.len(), 0);
}
#[test]
fn test_event_cursor_len_empty() {
let events = Events::<TestEvent>::default();
assert_eq!(events.get_cursor().len(&events), 0);
assert!(events.get_cursor().is_empty(&events));
}
#[test]
fn test_event_cursor_len_filled() {
let mut events = Events::<TestEvent>::default();
events.send(TestEvent { i: 0 });
assert_eq!(events.get_cursor().len(&events), 1);
assert!(!events.get_cursor().is_empty(&events));
}
#[cfg(feature = "multi_threaded")]
#[test]
fn test_event_cursor_par_read() {
use crate::prelude::*;
use core::sync::atomic::{AtomicUsize, Ordering};
#[derive(Resource)]
struct Counter(AtomicUsize);
let mut world = World::new();
world.init_resource::<Events<TestEvent>>();
for _ in 0..100 {
world.send_event(TestEvent { i: 1 });
}
let mut schedule = Schedule::default();
schedule.add_systems(
|mut cursor: Local<EventCursor<TestEvent>>,
events: Res<Events<TestEvent>>,
counter: ResMut<Counter>| {
cursor.par_read(&events).for_each(|event| {
counter.0.fetch_add(event.i, Ordering::Relaxed);
});
},
);
world.insert_resource(Counter(AtomicUsize::new(0)));
schedule.run(&mut world);
let counter = world.remove_resource::<Counter>().unwrap();
assert_eq!(counter.0.into_inner(), 100);
world.insert_resource(Counter(AtomicUsize::new(0)));
schedule.run(&mut world);
let counter = world.remove_resource::<Counter>().unwrap();
assert_eq!(
counter.0.into_inner(),
0,
"par_read should have consumed events but didn't"
);
}
#[cfg(feature = "multi_threaded")]
#[test]
fn test_event_cursor_par_read_mut() {
use crate::prelude::*;
use core::sync::atomic::{AtomicUsize, Ordering};
#[derive(Resource)]
struct Counter(AtomicUsize);
let mut world = World::new();
world.init_resource::<Events<TestEvent>>();
for _ in 0..100 {
world.send_event(TestEvent { i: 1 });
}
let mut schedule = Schedule::default();
schedule.add_systems(
|mut cursor: Local<EventCursor<TestEvent>>,
mut events: ResMut<Events<TestEvent>>,
counter: ResMut<Counter>| {
cursor.par_read_mut(&mut events).for_each(|event| {
event.i += 1;
counter.0.fetch_add(event.i, Ordering::Relaxed);
});
},
);
world.insert_resource(Counter(AtomicUsize::new(0)));
schedule.run(&mut world);
let counter = world.remove_resource::<Counter>().unwrap();
assert_eq!(counter.0.into_inner(), 200, "Initial run failed");
world.insert_resource(Counter(AtomicUsize::new(0)));
schedule.run(&mut world);
let counter = world.remove_resource::<Counter>().unwrap();
assert_eq!(
counter.0.into_inner(),
0,
"par_read_mut should have consumed events but didn't"
);
}
// Reader & Mutator
#[test]
fn ensure_reader_readonly() {
fn reader_system(_: EventReader<EmptyTestEvent>) {}
assert_is_read_only_system(reader_system);
}
#[test]
fn test_event_reader_iter_last() {
use bevy_ecs::prelude::*;
let mut world = World::new();
world.init_resource::<Events<TestEvent>>();
let mut reader =
IntoSystem::into_system(|mut events: EventReader<TestEvent>| -> Option<TestEvent> {
events.read().last().copied()
});
reader.initialize(&mut world);
let last = reader.run((), &mut world);
assert!(last.is_none(), "EventReader should be empty");
world.send_event(TestEvent { i: 0 });
let last = reader.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 = reader.run((), &mut world);
assert_eq!(last, Some(TestEvent { i: 3 }));
let last = reader.run((), &mut world);
assert!(last.is_none(), "EventReader should be empty");
}
#[test]
fn test_event_mutator_iter_last() {
use bevy_ecs::prelude::*;
let mut world = World::new();
world.init_resource::<Events<TestEvent>>();
let mut mutator =
IntoSystem::into_system(|mut events: EventMutator<TestEvent>| -> Option<TestEvent> {
events.read().last().copied()
});
mutator.initialize(&mut world);
let last = mutator.run((), &mut world);
assert!(last.is_none(), "EventMutator should be empty");
world.send_event(TestEvent { i: 0 });
let last = mutator.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 = mutator.run((), &mut world);
assert_eq!(last, Some(TestEvent { i: 3 }));
let last = mutator.run((), &mut world);
assert!(last.is_none(), "EventMutator should be empty");
}
#[allow(clippy::iter_nth_zero)]
#[test]
fn test_event_reader_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(|mut events: EventReader<TestEvent>| {
let mut iter = events.read();
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);
}
#[allow(clippy::iter_nth_zero)]
#[test]
fn test_event_mutator_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(|mut events: EventReader<TestEvent>| {
let mut iter = events.read();
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);
}
}