mm1_core/
envelope.rs

1use std::any::TypeId;
2use std::fmt;
3use std::sync::atomic::{AtomicU64, Ordering};
4
5use mm1_address::address::Address;
6pub use mm1_proc_macros::dispatch;
7use mm1_proto::Message;
8
9use crate::message::AnyMessage;
10use crate::tracing::TraceId;
11
12static ENVELOPE_SEQ_NO: AtomicU64 = AtomicU64::new(0);
13
14const DEFAULT_TTL: usize = 3;
15
16#[derive(Debug)]
17pub struct EnvelopeHeader {
18    pub to:       Address,
19    pub ttl:      usize,
20    pub priority: bool,
21
22    #[allow(dead_code)]
23    no:       u64,
24    #[allow(dead_code)]
25    trace_id: TraceId,
26}
27
28pub struct Envelope<M = AnyMessage> {
29    header:  EnvelopeHeader,
30    message: M,
31}
32
33impl EnvelopeHeader {
34    pub fn to_address(to: Address) -> Self {
35        Self {
36            to,
37            no: ENVELOPE_SEQ_NO.fetch_add(1, Ordering::Relaxed),
38            priority: false,
39            ttl: DEFAULT_TTL,
40            trace_id: TraceId::current(),
41        }
42    }
43
44    pub fn with_ttl(self, ttl: usize) -> Self {
45        Self { ttl, ..self }
46    }
47
48    pub fn with_trace_id(self, trace_id: TraceId) -> Self {
49        Self { trace_id, ..self }
50    }
51
52    pub fn with_priority(self, priority: bool) -> Self {
53        Self { priority, ..self }
54    }
55}
56
57impl EnvelopeHeader {
58    pub fn trace_id(&self) -> TraceId {
59        self.trace_id
60    }
61}
62
63impl<M> Envelope<M>
64where
65    M: Message,
66{
67    pub fn into_erased(self) -> Envelope<AnyMessage> {
68        let Self {
69            header: info,
70            message,
71        } = self;
72        let message = AnyMessage::new(message);
73        Envelope {
74            header: info,
75            message,
76        }
77    }
78}
79
80impl<M> Envelope<M> {
81    pub fn new(header: EnvelopeHeader, message: M) -> Self {
82        Self { header, message }
83    }
84
85    pub fn header(&self) -> &EnvelopeHeader {
86        &self.header
87    }
88}
89
90impl Envelope<AnyMessage> {
91    pub fn cast<M>(self) -> Result<Envelope<M>, Self>
92    where
93        M: Message,
94    {
95        let Self {
96            header: info,
97            message,
98        } = self;
99        match message.cast() {
100            Ok(message) => {
101                Ok(Envelope {
102                    header: info,
103                    message,
104                })
105            },
106            Err(message) => {
107                Err(Self {
108                    header: info,
109                    message,
110                })
111            },
112        }
113    }
114
115    pub fn peek<M>(&self) -> Option<&M>
116    where
117        M: Message,
118    {
119        self.message.peek()
120    }
121
122    pub fn is<M>(&self) -> bool
123    where
124        M: Message,
125    {
126        self.message.is::<M>()
127    }
128
129    pub fn tid(&self) -> TypeId {
130        self.message.tid()
131    }
132
133    pub fn message_name(&self) -> &str {
134        self.message.type_name()
135    }
136}
137impl<M> Envelope<M> {
138    pub fn take(self) -> (M, Envelope<()>) {
139        (
140            self.message,
141            Envelope {
142                header:  self.header,
143                message: (),
144            },
145        )
146    }
147}
148
149impl<M> fmt::Debug for Envelope<M>
150where
151    M: fmt::Debug,
152{
153    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154        f.debug_struct("Envelope")
155            .field("info", &self.header)
156            .field("message", &self.message)
157            .finish()
158    }
159}