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}