Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/message/message_reader.rs
6849 views
1
#[cfg(feature = "multi_threaded")]
2
use crate::message::MessageParIter;
3
use crate::{
4
message::{Message, MessageCursor, MessageIterator, MessageIteratorWithId, Messages},
5
system::{Local, Res, SystemParam},
6
};
7
8
/// Reads [`Message`]s of type `T` in order and tracks which messages have already been read.
9
///
10
/// # Concurrency
11
///
12
/// Unlike [`MessageWriter<T>`], systems with `MessageReader<T>` param can be executed concurrently
13
/// (but not concurrently with `MessageWriter<T>` or `MessageMutator<T>` systems for the same message type).
14
///
15
/// [`MessageWriter<T>`]: super::MessageWriter
16
#[derive(SystemParam, Debug)]
17
pub struct MessageReader<'w, 's, E: Message> {
18
pub(super) reader: Local<'s, MessageCursor<E>>,
19
#[system_param(validation_message = "Message not initialized")]
20
messages: Res<'w, Messages<E>>,
21
}
22
23
impl<'w, 's, E: Message> MessageReader<'w, 's, E> {
24
/// Iterates over the messages this [`MessageReader`] has not seen yet. This updates the
25
/// [`MessageReader`]'s message counter, which means subsequent message reads will not include messages
26
/// that happened before now.
27
pub fn read(&mut self) -> MessageIterator<'_, E> {
28
self.reader.read(&self.messages)
29
}
30
31
/// Like [`read`](Self::read), except also returning the [`MessageId`](super::MessageId) of the messages.
32
pub fn read_with_id(&mut self) -> MessageIteratorWithId<'_, E> {
33
self.reader.read_with_id(&self.messages)
34
}
35
36
/// Returns a parallel iterator over the messages this [`MessageReader`] has not seen yet.
37
/// See also [`for_each`](MessageParIter::for_each).
38
///
39
/// # Example
40
/// ```
41
/// # use bevy_ecs::prelude::*;
42
/// # use std::sync::atomic::{AtomicUsize, Ordering};
43
///
44
/// #[derive(Message)]
45
/// struct MyMessage {
46
/// value: usize,
47
/// }
48
///
49
/// #[derive(Resource, Default)]
50
/// struct Counter(AtomicUsize);
51
///
52
/// // setup
53
/// let mut world = World::new();
54
/// world.init_resource::<Messages<MyMessage>>();
55
/// world.insert_resource(Counter::default());
56
///
57
/// let mut schedule = Schedule::default();
58
/// schedule.add_systems(|mut messages: MessageReader<MyMessage>, counter: Res<Counter>| {
59
/// messages.par_read().for_each(|MyMessage { value }| {
60
/// counter.0.fetch_add(*value, Ordering::Relaxed);
61
/// });
62
/// });
63
/// for value in 0..100 {
64
/// world.write_message(MyMessage { value });
65
/// }
66
/// schedule.run(&mut world);
67
/// let Counter(counter) = world.remove_resource::<Counter>().unwrap();
68
/// // all messages were processed
69
/// assert_eq!(counter.into_inner(), 4950);
70
/// ```
71
#[cfg(feature = "multi_threaded")]
72
pub fn par_read(&mut self) -> MessageParIter<'_, E> {
73
self.reader.par_read(&self.messages)
74
}
75
76
/// Determines the number of messages available to be read from this [`MessageReader`] without consuming any.
77
pub fn len(&self) -> usize {
78
self.reader.len(&self.messages)
79
}
80
81
/// Returns `true` if there are no messages available to read.
82
///
83
/// # Example
84
///
85
/// The following example shows a useful pattern where some behavior is triggered if new messages are available.
86
/// [`MessageReader::clear()`] is used so the same messages don't re-trigger the behavior the next time the system runs.
87
///
88
/// ```
89
/// # use bevy_ecs::prelude::*;
90
/// #
91
/// #[derive(Message)]
92
/// struct Collision;
93
///
94
/// fn play_collision_sound(mut messages: MessageReader<Collision>) {
95
/// if !messages.is_empty() {
96
/// messages.clear();
97
/// // Play a sound
98
/// }
99
/// }
100
/// # bevy_ecs::system::assert_is_system(play_collision_sound);
101
/// ```
102
pub fn is_empty(&self) -> bool {
103
self.reader.is_empty(&self.messages)
104
}
105
106
/// Consumes all available messages.
107
///
108
/// This means these messages will not appear in calls to [`MessageReader::read()`] or
109
/// [`MessageReader::read_with_id()`] and [`MessageReader::is_empty()`] will return `true`.
110
///
111
/// For usage, see [`MessageReader::is_empty()`].
112
pub fn clear(&mut self) {
113
self.reader.clear(&self.messages);
114
}
115
}
116
117