swamp_message/lib.rs
1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/swamp
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5pub mod prelude;
6
7use std::{
8 any::{Any, TypeId},
9 collections::HashMap,
10 fmt::Debug,
11 marker::PhantomData,
12 slice::Iter,
13};
14
15use swamp_macros::Resource;
16use swamp_resource::Resource;
17use tracing::trace;
18
19/// Trait representing a message in the system.
20///
21/// Messages must be `'static` to allow for type-erased storage and must implement `Copy`,
22/// `Debug`, `Send`, and `Sync` to ensure they can be safely shared across threads and easily debugged.
23pub trait Message: 'static + Debug + Send + Sync {}
24
25/// Unique identifier for a specific message type.
26///
27/// This is primarily used for debugging purposes.
28#[derive(Debug)]
29pub struct MessageId<M: Message> {
30 /// Internal value representing the message ID.
31 ///
32 value: u16,
33
34 /// Phantom data to associate the ID with its message type.
35 _phantom: PhantomData<M>,
36}
37
38impl<M: Message> Copy for MessageId<M> {}
39
40impl<M: Message> Clone for MessageId<M> {
41 fn clone(&self) -> Self {
42 *self
43 }
44}
45
46impl<M: Message> MessageId<M> {
47 /// Creates a new `MessageId` with the given value.
48 #[must_use]
49 pub const fn new(value: u16) -> Self {
50 Self {
51 value,
52 _phantom: PhantomData,
53 }
54 }
55
56 /// Retrieves the underlying value of the `MessageId`.
57 #[must_use]
58 pub const fn value(&self) -> u16 {
59 self.value
60 }
61}
62
63/// Stores information about a message, including its ID and the message itself.
64///
65/// This struct is used internally to manage messages across different frames.
66#[derive(Debug)]
67struct MessageInfo<M: Message> {
68 /// Unique identifier for the message.
69 #[allow(unused)]
70 message_id: MessageId<M>,
71
72 /// The actual message data.
73 message: M,
74}
75
76/// Container for managing messages of a specific type.
77///
78/// This struct maintains separate lists for messages from the current and previous frames.
79#[derive(Default, Resource, Debug)]
80pub struct Messages<M: Message> {
81 /// Messages sent in the previous frame.
82 previous_frame_messages: Vec<MessageInfo<M>>,
83
84 /// Messages sent in the current frame.
85 current_messages: Vec<MessageInfo<M>>,
86}
87
88impl<M: Message> Messages<M> {
89 /// Creates a new `Messages` container.
90 #[must_use]
91 pub const fn new() -> Self {
92 Self {
93 previous_frame_messages: Vec::new(),
94 current_messages: Vec::new(),
95 }
96 }
97
98 /// Sends a new message, assigning it a unique `MessageId`.
99 ///
100 /// The message is added to the `current_messages` list.
101 ///
102 /// # Arguments
103 ///
104 /// * `message` - The message to be sent.
105 ///
106 /// # Returns
107 ///
108 /// A `MessageId` uniquely identifying the sent message.
109 pub fn send(&mut self, message: M) -> MessageId<M> {
110 let message_id = MessageId::new(self.current_messages.len() as u16);
111
112 trace!("Sending message: {:?}", message);
113
114 let message_info = MessageInfo {
115 message_id,
116 message,
117 };
118
119 self.current_messages.push(message_info);
120
121 message_id
122 }
123
124 /// Swaps the current and previous frame message lists.
125 ///
126 /// This should be called at the start of each new frame (update) to transition messages appropriately.
127 pub fn swap(&mut self) {
128 self.previous_frame_messages.clear();
129
130 std::mem::swap(
131 &mut self.previous_frame_messages,
132 &mut self.current_messages,
133 );
134
135 self.current_messages.clear();
136 }
137
138 /// Returns an iterator over the current frame's messages.
139 #[must_use]
140 pub fn iter_current(&self) -> MessagesIterator<M> {
141 MessagesIterator {
142 iter: self.current_messages.iter(),
143 }
144 }
145
146 /// Returns an iterator over the previous frame's messages.
147 #[must_use]
148 pub fn iter_previous(&self) -> MessagesIterator<M> {
149 MessagesIterator {
150 iter: self.previous_frame_messages.iter(),
151 }
152 }
153
154 /// Returns the number of messages in the current frame.
155 #[must_use]
156 pub fn len_current(&self) -> usize {
157 self.current_messages.len()
158 }
159
160 /// Returns the number of messages in the previous frame.
161 #[must_use]
162 pub fn len_previous(&self) -> usize {
163 self.previous_frame_messages.len()
164 }
165
166 /// Checks if there are no messages in the current frame.
167 #[must_use]
168 pub fn is_empty_current(&self) -> bool {
169 self.current_messages.is_empty()
170 }
171
172 /// Checks if there are no messages in the previous frame.
173 #[must_use]
174 pub fn is_empty_previous(&self) -> bool {
175 self.previous_frame_messages.is_empty()
176 }
177}
178
179/// Iterator over messages of a specific type.
180///
181/// This iterator yields references to messages, allowing for non-consuming traversal.
182pub struct MessagesIterator<'a, M: Message> {
183 iter: Iter<'a, MessageInfo<M>>,
184}
185
186impl<'a, M: Message> Iterator for MessagesIterator<'a, M> {
187 type Item = &'a M;
188
189 #[must_use]
190 fn next(&mut self) -> Option<Self::Item> {
191 self.iter.next().map(|message_info| &message_info.message)
192 }
193}
194
195impl<'a, M: Message> DoubleEndedIterator for MessagesIterator<'a, M> {
196 #[must_use]
197 fn next_back(&mut self) -> Option<Self::Item> {
198 self.iter
199 .next_back()
200 .map(|message_info| &message_info.message)
201 }
202}
203
204/// Trait for type-erased message containers.
205///
206/// This allows for storing heterogeneous `Messages<M>` containers within a single collection.
207pub trait MessageContainer: Any + Send + Sync {
208 /// Swaps the current and previous frame message lists.
209 fn swap(&mut self);
210
211 /// Provides a reference to the container as `Any` for downcasting.
212 fn as_any(&self) -> &dyn Any;
213
214 /// Provides a mutable reference to the container as `Any` for downcasting.
215 fn as_any_mut(&mut self) -> &mut dyn Any;
216}
217
218impl<M: Message> MessageContainer for Messages<M> {
219 fn swap(&mut self) {
220 self.swap();
221 }
222
223 fn as_any(&self) -> &dyn Any {
224 self
225 }
226
227 fn as_any_mut(&mut self) -> &mut dyn Any {
228 self
229 }
230}
231
232/// Storage for all message types.
233///
234/// This struct maintains a registry mapping each message type to its corresponding `Messages<M>` container.
235#[derive(Default)]
236pub struct MessageStorage {
237 registry: HashMap<TypeId, Box<dyn MessageContainer>>,
238}
239
240impl Debug for MessageStorage {
241 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
242 write!(f, "MessageStorage")
243 }
244}
245
246impl MessageStorage {
247 /// Creates a new, empty `MessageStorage`.
248 #[must_use]
249 pub fn new() -> Self {
250 Self {
251 registry: HashMap::new(),
252 }
253 }
254
255 /// Registers a new message type within the storage.
256 ///
257 /// # Type Parameters
258 ///
259 /// * `M` - The message type to register.
260 ///
261 /// # Example
262 ///
263 /// ```rust
264 /// use swamp_message::prelude::*;
265 ///
266 /// #[derive(Message, Debug, Copy, Clone)]
267 /// struct MyMessage;
268 ///
269 /// let mut storage = MessageStorage::new();
270 ///
271 /// storage.register_message_type::<MyMessage>();
272 /// ```
273 pub fn register_message_type<M: Message>(&mut self) {
274 let type_id = TypeId::of::<M>();
275 self.registry.insert(
276 type_id,
277 Box::new(Messages::<M>::new()) as Box<dyn MessageContainer>,
278 );
279 }
280
281 /// Retrieves a mutable reference to the `Messages<M>` container for the specified message type.
282 ///
283 /// Returns `None` if the message type has not been registered.
284 ///
285 /// # Type Parameters
286 ///
287 /// * `M` - The message type to retrieve.
288 ///
289 /// # Example
290 ///
291 /// ```rust
292 /// use swamp_message::prelude::*;
293 ///
294 /// #[derive(Message, Debug, Copy, Clone)]
295 /// struct MyMessage;
296 ///
297 /// let mut storage = MessageStorage::new();
298 ///
299 /// if let Some(messages) = storage.get_mut::<MyMessage>() {
300 /// // Use `messages` here
301 /// }
302 /// ```
303 #[must_use]
304 pub fn get_mut<M: Message>(&mut self) -> Option<&mut Messages<M>> {
305 self.registry
306 .get_mut(&TypeId::of::<M>())
307 .and_then(|boxed| boxed.as_any_mut().downcast_mut::<Messages<M>>())
308 }
309
310 /// Retrieves an immutable reference to the `Messages<M>` container for the specified message type.
311 ///
312 /// Returns `None` if the message type has not been registered.
313 ///
314 /// # Type Parameters
315 ///
316 /// * `M` - The message type to retrieve.
317 ///
318 /// # Example
319 ///
320 /// ```rust
321 /// use swamp_message::prelude::*;
322 ///
323 /// #[derive(Message, Debug, Copy, Clone)]
324 /// struct MyMessage;
325 ///
326 /// let mut storage = MessageStorage::new();
327 ///
328 /// if let Some(messages) = storage.get::<MyMessage>() {
329 /// // Use `messages` here
330 /// }
331 /// ```
332 #[must_use]
333 pub fn get<M: Message>(&self) -> Option<&Messages<M>> {
334 self.registry
335 .get(&TypeId::of::<M>())
336 .and_then(|boxed| boxed.as_any().downcast_ref::<Messages<M>>())
337 }
338
339 /// Swaps the current and previous frame message lists for all registered message types.
340 ///
341 /// This should be called at the start of each new frame to transition messages appropriately.
342 ///
343 /// **Note:** The order in which message queues are swapped is not deterministic due to the nature of `HashMap`.
344 /// This is generally acceptable but should be considered if order matters.
345 pub fn swap_all(&mut self) {
346 for messages_any in &mut self.registry.values_mut() {
347 messages_any.swap();
348 }
349 }
350
351 /// Sends a message of a specific type.
352 ///
353 /// This method abstracts over the message type, automatically handling registration if necessary.
354 ///
355 /// # Type Parameters
356 ///
357 /// * `M` - The message type to send.
358 ///
359 /// # Arguments
360 ///
361 /// * `message` - The message to be sent.
362 ///
363 /// # Returns
364 ///
365 /// A `MessageId` uniquely identifying the sent message.
366 ///
367 /// # Example
368 ///
369 /// ```rust
370 /// use swamp_message::prelude::*;
371 ///
372 /// #[derive(Message, Debug, Copy, Clone)]
373 /// struct MyMessage;
374 ///
375 /// let mut storage = MessageStorage::new();
376 ///
377 /// let msg_id = storage.send(MyMessage { /* fields */ });
378 /// ```
379 #[allow(clippy::missing_panics_doc)]
380 pub fn send<M: Message>(&mut self, message: M) -> MessageId<M> {
381 // Ensure the message type is registered.
382 if !self.registry.contains_key(&TypeId::of::<M>()) {
383 self.register_message_type::<M>();
384 }
385
386 // It's safe to unwrap here because we just registered the type if it wasn't present.
387 self.get_mut::<M>()
388 .expect("Message type should be registered")
389 .send(message)
390 }
391
392 /// Iterates over all messages of a specific type in the current frame.
393 ///
394 /// # Type Parameters
395 ///
396 /// * `M` - The message type to iterate over.
397 ///
398 /// # Returns
399 ///
400 /// An iterator over references to messages of type `M` in the current frame.
401 ///
402 /// # Example
403 ///
404 /// ```rust
405 /// use swamp_message::prelude::*;
406 ///
407 /// #[derive(Message, Debug, Copy, Clone)]
408 /// struct MyMessage;
409 ///
410 /// let mut storage = MessageStorage::new();
411 ///
412 /// for message in storage.iter_current::<MyMessage>() {
413 /// // Process `message`
414 /// }
415 /// ```
416 #[must_use]
417 pub fn iter_current<M: Message>(&self) -> Option<MessagesIterator<M>> {
418 self.get::<M>().map(|messages| messages.iter_current())
419 }
420
421 /// Iterates over all messages of a specific type in the previous frame.
422 ///
423 /// # Type Parameters
424 ///
425 /// * `M` - The message type to iterate over.
426 ///
427 /// # Returns
428 ///
429 /// An iterator over references to messages of type `M` in the previous frame.
430 ///
431 /// # Example
432 ///
433 /// ```rust
434 /// use swamp_message::prelude::*;
435 ///
436 /// #[derive(Message, Debug, Copy, Clone)]
437 /// struct MyMessage;
438 ///
439 /// let mut storage = MessageStorage::new();
440 ///
441 /// for message in storage.iter_previous::<MyMessage>() {
442 /// // Process `message`
443 /// }
444 /// ```
445 #[must_use]
446 pub fn iter_previous<M: Message>(&self) -> Option<MessagesIterator<M>> {
447 self.get::<M>().map(|messages| messages.iter_previous())
448 }
449}