Skip to main content

salish/
message.rs

1use std::{
2    any::{type_name, Any, TypeId},
3    hash::{DefaultHasher, Hasher as _},
4    marker::PhantomData,
5    sync::Arc,
6};
7
8use crate::traits::{
9    internal::SalishMessageInternal as _, EndpointAddress, Payload, SalishMessage,
10};
11
12#[derive(Clone)]
13pub struct Message
14where
15    Self: Send + Sync,
16{
17    dest: Destination<<<Self as SalishMessage>::Endpoint as EndpointAddress>::Addr>,
18    data: Arc<Box<dyn Any + Send + Sync>>,
19    type_name: &'static str,
20}
21
22impl std::fmt::Debug for Message {
23    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24        f.debug_struct("Message")
25            .field("dest", &self.dest)
26            .field("payload_type_id", &self.payload_type())
27            .field("payload_type_name", &self.type_name)
28            .finish()
29    }
30}
31
32impl Message {
33    /// Create a new message with destination set to [`Destination::Any`].
34    /// This will route the message to any registered receiver for this message type
35    pub fn new<T: Payload + 'static>(data: T) -> Self {
36        Self::new_to(Destination::Any, data)
37    }
38
39    /// Create a new message with destination specified by `dest`
40    pub fn new_to<T: Payload + 'static>(
41        dest: Destination<<<Self as SalishMessage>::Endpoint as EndpointAddress>::Addr>,
42        data: T,
43    ) -> Self {
44        Self {
45            dest,
46            data: Arc::new(Box::new(data)),
47            type_name: type_name::<T>(),
48        }
49    }
50
51    /// Check if the payload is of type T
52    pub fn is_type<T: 'static>(&self) -> bool {
53        TypeId::of::<T>() == self.payload_type()
54    }
55
56    /// Get the destination of this message
57    pub fn dest(
58        &self,
59    ) -> &Destination<<<Self as SalishMessage>::Endpoint as EndpointAddress>::Addr> {
60        &self.dest
61    }
62}
63
64#[derive(Clone, Debug)]
65pub enum Destination<Addr> {
66    /// Message destined to any endpoint listening to a message type
67    Any,
68
69    /// Message destined to a specific endpoint
70    //Endpoint(Arc<dyn EndpointAddress<Addr = Addr>>),
71    Endpoint(Addr),
72}
73
74impl<Addr: 'static> Destination<Addr> {
75    pub fn any() -> Self {
76        Self::Any
77    }
78
79    pub fn endpoint(addr: Addr) -> Self {
80        Self::Endpoint(addr)
81    }
82}
83
84#[derive(Debug, Clone)]
85struct HashEndpoint<'a, T>
86where
87    T: std::fmt::Debug + std::hash::Hash + Send + Sync,
88{
89    h: &'a T,
90    _phantom: PhantomData<T>,
91}
92
93impl<'a, T: std::hash::Hash> EndpointAddress for HashEndpoint<'a, T>
94where
95    T: std::fmt::Debug + std::hash::Hash + Send + Sync,
96{
97    type Addr = u64;
98    fn addr(&self) -> Self::Addr {
99        let mut hasher = DefaultHasher::new();
100        self.h.hash(&mut hasher);
101        hasher.finish()
102    }
103}
104
105impl EndpointAddress for u64 {
106    type Addr = u64;
107
108    fn addr(&self) -> Self::Addr {
109        *self
110    }
111}
112
113impl SalishMessage for Message {
114    type Endpoint = u64;
115
116    /// Return the payload to internal trait methods as &dyn Any
117    fn as_any(&self) -> &dyn Any {
118        &**self.data
119    }
120}