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;
10
11static ENVELOPE_SEQ_NO: AtomicU64 = AtomicU64::new(0);
12
13const DEFAULT_TTL: usize = 3;
14
15#[derive(Debug)]
16pub struct EnvelopeHeader {
17 pub to: Address,
18 pub ttl: usize,
19
20 #[allow(dead_code)]
21 no: u64,
22 #[allow(dead_code)]
23 trace_id: Option<u64>,
24 #[allow(dead_code)]
25 correlation_id: Option<u64>,
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 ttl: DEFAULT_TTL,
39 trace_id: None,
40 correlation_id: None,
41 }
42 }
43
44 pub fn with_ttl(self, ttl: usize) -> Self {
45 Self { ttl, ..self }
46 }
47}
48
49impl<M> Envelope<M>
50where
51 M: Message,
52{
53 pub fn into_erased(self) -> Envelope<AnyMessage> {
54 let Self {
55 header: info,
56 message,
57 } = self;
58 let message = AnyMessage::new(message);
59 Envelope {
60 header: info,
61 message,
62 }
63 }
64}
65
66impl<M> Envelope<M> {
67 pub fn new(header: EnvelopeHeader, message: M) -> Self {
68 Self { header, message }
69 }
70
71 pub fn header(&self) -> &EnvelopeHeader {
72 &self.header
73 }
74}
75
76impl Envelope<AnyMessage> {
77 pub fn cast<M>(self) -> Result<Envelope<M>, Self>
78 where
79 M: Message,
80 {
81 let Self {
82 header: info,
83 message,
84 } = self;
85 match message.cast() {
86 Ok(message) => {
87 Ok(Envelope {
88 header: info,
89 message,
90 })
91 },
92 Err(message) => {
93 Err(Self {
94 header: info,
95 message,
96 })
97 },
98 }
99 }
100
101 pub fn peek<M>(&self) -> Option<&M>
102 where
103 M: Message,
104 {
105 self.message.peek()
106 }
107
108 pub fn is<M>(&self) -> bool
109 where
110 M: Message,
111 {
112 self.message.is::<M>()
113 }
114
115 pub fn tid(&self) -> TypeId {
116 self.message.tid()
117 }
118
119 pub fn message_name(&self) -> &'static str {
120 self.message.type_name()
121 }
122}
123impl<M> Envelope<M> {
124 pub fn take(self) -> (M, Envelope<()>) {
125 (
126 self.message,
127 Envelope {
128 header: self.header,
129 message: (),
130 },
131 )
132 }
133}
134
135impl<M> fmt::Debug for Envelope<M>
136where
137 M: fmt::Debug,
138{
139 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140 f.debug_struct("Envelope")
141 .field("info", &self.header)
142 .field("message", &self.message)
143 .finish()
144 }
145}