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}