Skip to main content

limnus_message/
lib.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/limnus
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 limnus_macros::Resource;
16use limnus_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 const 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 const 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 const 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 const 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    fn next(&mut self) -> Option<Self::Item> {
190        self.iter.next().map(|message_info| &message_info.message)
191    }
192}
193
194impl<M: Message> DoubleEndedIterator for MessagesIterator<'_, M> {
195    fn next_back(&mut self) -> Option<Self::Item> {
196        self.iter
197            .next_back()
198            .map(|message_info| &message_info.message)
199    }
200}
201
202/// Trait for type-erased message containers.
203///
204/// This allows for storing heterogeneous `Messages<M>` containers within a single collection.
205pub trait MessageContainer: Any + Send + Sync {
206    /// Swaps the current and previous frame message lists.
207    fn swap(&mut self);
208
209    /// Provides a reference to the container as `Any` for downcasting.
210    fn as_any(&self) -> &dyn Any;
211
212    /// Provides a mutable reference to the container as `Any` for downcasting.
213    fn as_any_mut(&mut self) -> &mut dyn Any;
214}
215
216impl<M: Message> MessageContainer for Messages<M> {
217    fn swap(&mut self) {
218        self.swap();
219    }
220
221    fn as_any(&self) -> &dyn Any {
222        self
223    }
224
225    fn as_any_mut(&mut self) -> &mut dyn Any {
226        self
227    }
228}
229
230/// Storage for all message types.
231///
232/// This struct maintains a registry mapping each message type to its corresponding `Messages<M>` container.
233#[derive(Default)]
234pub struct MessageStorage {
235    registry: HashMap<TypeId, Box<dyn MessageContainer>>,
236}
237
238impl Debug for MessageStorage {
239    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
240        write!(f, "MessageStorage")
241    }
242}
243
244impl MessageStorage {
245    /// Creates a new, empty `MessageStorage`.
246    #[must_use]
247    pub fn new() -> Self {
248        Self {
249            registry: HashMap::new(),
250        }
251    }
252
253    /// Registers a new message type within the storage.
254    ///
255    /// # Type Parameters
256    ///
257    /// * `M` - The message type to register.
258    ///
259    /// # Example
260    ///
261    /// ```rust
262    /// use limnus_message::prelude::*;
263    ///
264    /// #[derive(Message, Debug, Copy, Clone)]
265    /// struct MyMessage;
266    ///
267    /// let mut storage = MessageStorage::new();
268    ///
269    /// storage.register_message_type::<MyMessage>();
270    /// ```
271    pub fn register_message_type<M: Message>(&mut self) {
272        let type_id = TypeId::of::<M>();
273        self.registry.insert(
274            type_id,
275            Box::new(Messages::<M>::new()) as Box<dyn MessageContainer>,
276        );
277    }
278
279    /// Retrieves a mutable reference to the `Messages<M>` container for the specified message type.
280    ///
281    /// Returns `None` if the message type has not been registered.
282    ///
283    /// # Type Parameters
284    ///
285    /// * `M` - The message type to retrieve.
286    ///
287    /// # Example
288    ///
289    /// ```rust
290    /// use limnus_message::prelude::*;
291    ///
292    /// #[derive(Message, Debug, Copy, Clone)]
293    /// struct MyMessage;
294    ///
295    /// let mut storage = MessageStorage::new();
296    ///
297    /// if let Some(messages) = storage.get_mut::<MyMessage>() {
298    ///     // Use `messages` here
299    /// }
300    /// ```
301    #[must_use]
302    pub fn get_mut<M: Message>(&mut self) -> Option<&mut Messages<M>> {
303        self.registry
304            .get_mut(&TypeId::of::<M>())
305            .and_then(|boxed| boxed.as_any_mut().downcast_mut::<Messages<M>>())
306    }
307
308    /// Retrieves an immutable reference to the `Messages<M>` container for the specified message type.
309    ///
310    /// Returns `None` if the message type has not been registered.
311    ///
312    /// # Type Parameters
313    ///
314    /// * `M` - The message type to retrieve.
315    ///
316    /// # Example
317    ///
318    /// ```rust
319    /// use limnus_message::prelude::*;
320    ///
321    /// #[derive(Message, Debug, Copy, Clone)]
322    /// struct MyMessage;
323    ///
324    /// let mut storage = MessageStorage::new();
325    ///
326    /// if let Some(messages) = storage.get::<MyMessage>() {
327    ///     // Use `messages` here
328    /// }
329    /// ```
330    #[must_use]
331    pub fn get<M: Message>(&self) -> Option<&Messages<M>> {
332        self.registry
333            .get(&TypeId::of::<M>())
334            .and_then(|boxed| boxed.as_any().downcast_ref::<Messages<M>>())
335    }
336
337    /// Swaps the current and previous frame message lists for all registered message types.
338    ///
339    /// This should be called at the start of each new frame to transition messages appropriately.
340    ///
341    /// **Note:** The order in which message queues are swapped is not deterministic due to the nature of `HashMap`.
342    /// This is generally acceptable but should be considered if order matters.
343    pub fn swap_all(&mut self) {
344        for messages_any in &mut self.registry.values_mut() {
345            messages_any.swap();
346        }
347    }
348
349    /// Sends a message of a specific type.
350    ///
351    /// This method abstracts over the message type, automatically handling registration if necessary.
352    ///
353    /// # Type Parameters
354    ///
355    /// * `M` - The message type to send.
356    ///
357    /// # Arguments
358    ///
359    /// * `message` - The message to be sent.
360    ///
361    /// # Returns
362    ///
363    /// A `MessageId` uniquely identifying the sent message.
364    ///
365    /// # Example
366    ///
367    /// ```rust
368    /// use limnus_message::prelude::*;
369    ///
370    /// #[derive(Message, Debug, Copy, Clone)]
371    /// struct MyMessage;
372    ///
373    /// let mut storage = MessageStorage::new();
374    ///
375    /// let msg_id = storage.send(MyMessage { /* fields */ });
376    /// ```
377    #[allow(clippy::missing_panics_doc)]
378    pub fn send<M: Message>(&mut self, message: M) -> MessageId<M> {
379        // Ensure the message type is registered.
380        if !self.registry.contains_key(&TypeId::of::<M>()) {
381            self.register_message_type::<M>();
382        }
383
384        // It's safe to unwrap here because we just registered the type if it wasn't present.
385        self.get_mut::<M>()
386            .expect("Message type should be registered")
387            .send(message)
388    }
389
390    /// Iterates over all messages of a specific type in the current frame.
391    ///
392    /// # Type Parameters
393    ///
394    /// * `M` - The message type to iterate over.
395    ///
396    /// # Returns
397    ///
398    /// An iterator over references to messages of type `M` in the current frame.
399    ///
400    /// # Example
401    ///
402    /// ```rust
403    /// use limnus_message::prelude::*;
404    ///
405    /// #[derive(Message, Debug, Copy, Clone)]
406    /// struct MyMessage;
407    ///
408    /// let mut storage = MessageStorage::new();
409    ///
410    /// for message in storage.iter_current::<MyMessage>() {
411    ///     // Process `message`
412    /// }
413    /// ```
414    #[must_use]
415    pub fn iter_current<M: Message>(&self) -> Option<MessagesIterator<'_, M>> {
416        self.get::<M>().map(|messages| messages.iter_current())
417    }
418
419    /// Iterates over all messages of a specific type in the previous frame.
420    ///
421    /// # Type Parameters
422    ///
423    /// * `M` - The message type to iterate over.
424    ///
425    /// # Returns
426    ///
427    /// An iterator over references to messages of type `M` in the previous frame.
428    ///
429    /// # Example
430    ///
431    /// ```rust
432    /// use limnus_message::prelude::*;
433    ///
434    /// #[derive(Message, Debug, Copy, Clone)]
435    /// struct MyMessage;
436    ///
437    /// let mut storage = MessageStorage::new();
438    ///
439    /// for message in storage.iter_previous::<MyMessage>() {
440    ///     // Process `message`
441    /// }
442    /// ```
443    #[must_use]
444    pub fn iter_previous<M: Message>(&self) -> Option<MessagesIterator<'_, M>> {
445        self.get::<M>().map(|messages| messages.iter_previous())
446    }
447}