pub mod prelude;
use std::{
any::{Any, TypeId},
collections::HashMap,
fmt::Debug,
marker::PhantomData,
slice::Iter,
};
use limnus_macros::Resource;
use limnus_resource::Resource;
use tracing::trace;
pub trait Message: 'static + Debug + Send + Sync {}
#[derive(Debug)]
pub struct MessageId<M: Message> {
value: u16,
_phantom: PhantomData<M>,
}
impl<M: Message> Copy for MessageId<M> {}
impl<M: Message> Clone for MessageId<M> {
fn clone(&self) -> Self {
*self
}
}
impl<M: Message> MessageId<M> {
#[must_use]
pub const fn new(value: u16) -> Self {
Self {
value,
_phantom: PhantomData,
}
}
#[must_use]
pub const fn value(&self) -> u16 {
self.value
}
}
#[derive(Debug)]
struct MessageInfo<M: Message> {
#[allow(unused)]
message_id: MessageId<M>,
message: M,
}
#[derive(Default, Resource, Debug)]
pub struct Messages<M: Message> {
previous_frame_messages: Vec<MessageInfo<M>>,
current_messages: Vec<MessageInfo<M>>,
}
impl<M: Message> Messages<M> {
#[must_use]
pub const fn new() -> Self {
Self {
previous_frame_messages: Vec::new(),
current_messages: Vec::new(),
}
}
pub fn send(&mut self, message: M) -> MessageId<M> {
let message_id = MessageId::new(self.current_messages.len() as u16);
trace!("Sending message: {:?}", message);
let message_info = MessageInfo {
message_id,
message,
};
self.current_messages.push(message_info);
message_id
}
pub fn swap(&mut self) {
self.previous_frame_messages.clear();
std::mem::swap(
&mut self.previous_frame_messages,
&mut self.current_messages,
);
self.current_messages.clear();
}
#[must_use]
pub fn iter_current(&self) -> MessagesIterator<'_, M> {
MessagesIterator {
iter: self.current_messages.iter(),
}
}
#[must_use]
pub fn iter_previous(&self) -> MessagesIterator<'_, M> {
MessagesIterator {
iter: self.previous_frame_messages.iter(),
}
}
#[must_use]
pub const fn len_current(&self) -> usize {
self.current_messages.len()
}
#[must_use]
pub const fn len_previous(&self) -> usize {
self.previous_frame_messages.len()
}
#[must_use]
pub const fn is_empty_current(&self) -> bool {
self.current_messages.is_empty()
}
#[must_use]
pub const fn is_empty_previous(&self) -> bool {
self.previous_frame_messages.is_empty()
}
}
pub struct MessagesIterator<'a, M: Message> {
iter: Iter<'a, MessageInfo<M>>,
}
impl<'a, M: Message> Iterator for MessagesIterator<'a, M> {
type Item = &'a M;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|message_info| &message_info.message)
}
}
impl<M: Message> DoubleEndedIterator for MessagesIterator<'_, M> {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter
.next_back()
.map(|message_info| &message_info.message)
}
}
pub trait MessageContainer: Any + Send + Sync {
fn swap(&mut self);
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
impl<M: Message> MessageContainer for Messages<M> {
fn swap(&mut self) {
self.swap();
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
#[derive(Default)]
pub struct MessageStorage {
registry: HashMap<TypeId, Box<dyn MessageContainer>>,
}
impl Debug for MessageStorage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "MessageStorage")
}
}
impl MessageStorage {
#[must_use]
pub fn new() -> Self {
Self {
registry: HashMap::new(),
}
}
pub fn register_message_type<M: Message>(&mut self) {
let type_id = TypeId::of::<M>();
self.registry.insert(
type_id,
Box::new(Messages::<M>::new()) as Box<dyn MessageContainer>,
);
}
#[must_use]
pub fn get_mut<M: Message>(&mut self) -> Option<&mut Messages<M>> {
self.registry
.get_mut(&TypeId::of::<M>())
.and_then(|boxed| boxed.as_any_mut().downcast_mut::<Messages<M>>())
}
#[must_use]
pub fn get<M: Message>(&self) -> Option<&Messages<M>> {
self.registry
.get(&TypeId::of::<M>())
.and_then(|boxed| boxed.as_any().downcast_ref::<Messages<M>>())
}
pub fn swap_all(&mut self) {
for messages_any in &mut self.registry.values_mut() {
messages_any.swap();
}
}
#[allow(clippy::missing_panics_doc)]
pub fn send<M: Message>(&mut self, message: M) -> MessageId<M> {
if !self.registry.contains_key(&TypeId::of::<M>()) {
self.register_message_type::<M>();
}
self.get_mut::<M>()
.expect("Message type should be registered")
.send(message)
}
#[must_use]
pub fn iter_current<M: Message>(&self) -> Option<MessagesIterator<'_, M>> {
self.get::<M>().map(|messages| messages.iter_current())
}
#[must_use]
pub fn iter_previous<M: Message>(&self) -> Option<MessagesIterator<'_, M>> {
self.get::<M>().map(|messages| messages.iter_previous())
}
}