Skip to main content

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}