bevy_ecs/message/message_writer.rs
1use crate::{
2 message::{Message, MessageId, Messages, WriteBatchIds},
3 system::{ResMut, SystemParam},
4};
5
6/// Writes [`Message`]s of type `T`.
7///
8/// # Usage
9///
10/// `MessageWriter`s are usually declared as a [`SystemParam`].
11/// ```
12/// # use bevy_ecs::prelude::*;
13///
14/// #[derive(Message)]
15/// pub struct MyMessage; // Custom message type.
16/// fn my_system(mut writer: MessageWriter<MyMessage>) {
17/// writer.write(MyMessage);
18/// }
19///
20/// # bevy_ecs::system::assert_is_system(my_system);
21/// ```
22///
23/// # Concurrency
24///
25/// `MessageWriter` param has [`ResMut<Messages<T>>`](Messages) inside. So two systems declaring `MessageWriter<T>` params
26/// for the same message type won't be executed concurrently.
27///
28/// # Untyped messages
29///
30/// `MessageWriter` can only write messages of one specific type, which must be known at compile-time.
31/// This is not a problem most of the time, but you may find a situation where you cannot know
32/// ahead of time every kind of message you'll need to write. In this case, you can use the "type-erased message" pattern.
33///
34/// ```
35/// # use bevy_ecs::{prelude::*, message::Messages};
36/// # #[derive(Message)]
37/// # pub struct MyMessage;
38/// fn write_untyped(mut commands: Commands) {
39/// // Write a message of a specific type without having to declare that
40/// // type as a SystemParam.
41/// //
42/// // Effectively, we're just moving the type parameter from the /type/ to the /method/,
43/// // which allows one to do all kinds of clever things with type erasure, such as sending
44/// // custom messages to unknown 3rd party plugins (modding API).
45/// //
46/// // NOTE: the message won't actually be sent until commands get applied during
47/// // apply_deferred.
48/// commands.queue(|w: &mut World| {
49/// w.write_message(MyMessage);
50/// });
51/// }
52/// ```
53/// Note that this is considered *non-idiomatic*, and should only be used when `MessageWriter` will not work.
54///
55/// [`Observer`]: crate::observer::Observer
56#[derive(SystemParam)]
57pub struct MessageWriter<'w, E: Message> {
58 #[system_param(validation_message = "Message not initialized")]
59 messages: ResMut<'w, Messages<E>>,
60}
61
62impl<'w, E: Message> MessageWriter<'w, E> {
63 /// Writes an `message`, which can later be read by [`MessageReader`](super::MessageReader)s.
64 /// This method returns the [ID](`MessageId`) of the written `message`.
65 ///
66 /// See [`Messages`] for details.
67 #[doc(alias = "send")]
68 #[track_caller]
69 pub fn write(&mut self, message: E) -> MessageId<E> {
70 self.messages.write(message)
71 }
72
73 /// Writes a list of `messages` all at once, which can later be read by [`MessageReader`](super::MessageReader)s.
74 /// This is more efficient than writing each message individually.
75 /// This method returns the [IDs](`MessageId`) of the written `messages`.
76 ///
77 /// See [`Messages`] for details.
78 #[doc(alias = "send_batch")]
79 #[track_caller]
80 pub fn write_batch(&mut self, messages: impl IntoIterator<Item = E>) -> WriteBatchIds<E> {
81 self.messages.write_batch(messages)
82 }
83
84 /// Writes the default value of the message. Useful when the message is an empty struct.
85 /// This method returns the [ID](`MessageId`) of the written `message`.
86 ///
87 /// See [`Messages`] for details.
88 #[doc(alias = "send_default")]
89 #[track_caller]
90 pub fn write_default(&mut self) -> MessageId<E>
91 where
92 E: Default,
93 {
94 self.messages.write_default()
95 }
96}