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