Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/message/mod.rs
6849 views
1
//! [`Message`] functionality.
2
3
mod iterators;
4
mod message_cursor;
5
mod message_mutator;
6
mod message_reader;
7
mod message_registry;
8
mod message_writer;
9
mod messages;
10
mod mut_iterators;
11
mod update;
12
13
pub use iterators::*;
14
pub use message_cursor::*;
15
pub use message_mutator::*;
16
pub use message_reader::*;
17
pub use message_registry::*;
18
pub use message_writer::*;
19
pub use messages::*;
20
pub use mut_iterators::*;
21
pub use update::*;
22
23
pub use bevy_ecs_macros::Message;
24
25
use crate::change_detection::MaybeLocation;
26
#[cfg(feature = "bevy_reflect")]
27
use bevy_reflect::Reflect;
28
use core::{
29
cmp::Ordering,
30
fmt,
31
hash::{Hash, Hasher},
32
marker::PhantomData,
33
};
34
35
/// A buffered message for pull-based event handling.
36
///
37
/// Messages can be written with [`MessageWriter`] and read using the [`MessageReader`] system parameter.
38
/// Messages are stored in the [`Messages<M>`] resource, and require periodically polling the world for new messages,
39
/// typically in a system that runs as part of a schedule.
40
///
41
/// While the polling imposes a small overhead, messages are useful for efficiently batch processing
42
/// a large number of messages at once. For cases like these, messages can be more efficient than [`Event`]s (which are handled via [`Observer`]s).
43
///
44
/// Unlike [`Event`]s triggered for observers, messages are evaluated at fixed points in the schedule
45
/// rather than immediately when they are sent. This allows for more predictable scheduling, and deferring
46
/// message processing to a later point in time.
47
///
48
/// Messages must be thread-safe.
49
///
50
/// # Usage
51
///
52
/// The [`Message`] trait can be derived:
53
///
54
/// ```
55
/// # use bevy_ecs::prelude::*;
56
/// #
57
/// #[derive(Message)]
58
/// struct Greeting(String);
59
/// ```
60
///
61
/// The message can then be written to the message buffer using a [`MessageWriter`]:
62
///
63
/// ```
64
/// # use bevy_ecs::prelude::*;
65
/// #
66
/// # #[derive(Message)]
67
/// # struct Greeting(String);
68
/// #
69
/// fn write_hello(mut writer: MessageWriter<Greeting>) {
70
/// writer.write(Greeting("Hello!".to_string()));
71
/// }
72
/// ```
73
///
74
/// Messages can be efficiently read using a [`MessageReader`]:
75
///
76
/// ```
77
/// # use bevy_ecs::prelude::*;
78
/// #
79
/// # #[derive(Message)]
80
/// # struct Greeting(String);
81
/// #
82
/// fn read_messages(mut reader: MessageReader<Greeting>) {
83
/// // Process all messages of type `Greeting`.
84
/// for Greeting(greeting) in reader.read() {
85
/// println!("{greeting}");
86
/// }
87
/// }
88
/// ```
89
/// [`Event`]: crate::event::Event
90
/// [`Observer`]: crate::observer::Observer
91
#[diagnostic::on_unimplemented(
92
message = "`{Self}` is not an `Message`",
93
label = "invalid `Message`",
94
note = "consider annotating `{Self}` with `#[derive(Message)]`"
95
)]
96
pub trait Message: Send + Sync + 'static {}
97
98
#[derive(Debug)]
99
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
100
pub(crate) struct MessageInstance<M: Message> {
101
pub message_id: MessageId<M>,
102
pub message: M,
103
}
104
105
/// A [`MessageId`] uniquely identifies a message stored in a specific [`World`].
106
///
107
/// A [`MessageId`] can, among other things, be used to trace the flow of a [`Message`] from the point it was
108
/// sent to the point it was processed. [`MessageId`]s increase monotonically by write order.
109
///
110
/// [`World`]: crate::world::World
111
#[cfg_attr(
112
feature = "bevy_reflect",
113
derive(Reflect),
114
reflect(Clone, Debug, PartialEq, Hash)
115
)]
116
pub struct MessageId<M: Message> {
117
/// Uniquely identifies the message associated with this ID.
118
// This value corresponds to the order in which each message was written to the world.
119
pub id: usize,
120
/// The source code location that triggered this message.
121
pub caller: MaybeLocation,
122
#[cfg_attr(feature = "bevy_reflect", reflect(ignore, clone))]
123
pub(super) _marker: PhantomData<M>,
124
}
125
126
impl<M: Message> Copy for MessageId<M> {}
127
128
impl<M: Message> Clone for MessageId<M> {
129
fn clone(&self) -> Self {
130
*self
131
}
132
}
133
134
impl<M: Message> fmt::Display for MessageId<M> {
135
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
136
<Self as fmt::Debug>::fmt(self, f)
137
}
138
}
139
140
impl<M: Message> fmt::Debug for MessageId<M> {
141
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
142
write!(
143
f,
144
"message<{}>#{}",
145
core::any::type_name::<M>().split("::").last().unwrap(),
146
self.id,
147
)
148
}
149
}
150
151
impl<M: Message> PartialEq for MessageId<M> {
152
fn eq(&self, other: &Self) -> bool {
153
self.id == other.id
154
}
155
}
156
157
impl<M: Message> Eq for MessageId<M> {}
158
159
impl<M: Message> PartialOrd for MessageId<M> {
160
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
161
Some(self.cmp(other))
162
}
163
}
164
165
impl<M: Message> Ord for MessageId<M> {
166
fn cmp(&self, other: &Self) -> Ordering {
167
self.id.cmp(&other.id)
168
}
169
}
170
171
impl<M: Message> Hash for MessageId<M> {
172
fn hash<H: Hasher>(&self, state: &mut H) {
173
Hash::hash(&self.id, state);
174
}
175
}
176
177