elfo_core/
envelope.rs

1use quanta::Instant;
2
3use crate::{
4    addr::Addr,
5    address_book::AddressBook,
6    message::{AnyMessage, Message},
7    request_table::{RequestId, ResponseToken},
8    trace_id::TraceId,
9};
10
11// TODO: use granular messages instead of `SmallBox`.
12#[derive(Debug)]
13pub struct Envelope<M = AnyMessage> {
14    created_time: Instant, // Now used also as a sent time.
15    trace_id: TraceId,
16    kind: MessageKind,
17    message: M,
18}
19
20assert_impl_all!(Envelope: Send);
21assert_eq_size!(Envelope, [u8; 256]);
22
23#[derive(Debug)]
24pub(crate) enum MessageKind {
25    Regular { sender: Addr },
26    RequestAny(ResponseToken<()>),
27    RequestAll(ResponseToken<()>),
28    Response { sender: Addr, request_id: RequestId },
29}
30
31impl<M> Envelope<M> {
32    #[inline]
33    pub fn trace_id(&self) -> TraceId {
34        self.trace_id
35    }
36
37    #[inline]
38    pub fn message(&self) -> &M {
39        &self.message
40    }
41
42    pub(crate) fn message_kind(&self) -> &MessageKind {
43        &self.kind
44    }
45
46    pub(crate) fn created_time(&self) -> Instant {
47        self.created_time
48    }
49
50    #[inline]
51    pub fn sender(&self) -> Addr {
52        match &self.kind {
53            MessageKind::Regular { sender } => *sender,
54            MessageKind::RequestAny(token) => token.sender,
55            MessageKind::RequestAll(token) => token.sender,
56            MessageKind::Response { sender, .. } => *sender,
57        }
58    }
59}
60
61impl<M: Message> Envelope<M> {
62    pub(crate) fn new(message: M, kind: MessageKind) -> Self {
63        Self::with_trace_id(message, kind, crate::scope::trace_id())
64    }
65
66    pub(crate) fn with_trace_id(message: M, kind: MessageKind, trace_id: TraceId) -> Self {
67        Self {
68            created_time: Instant::now(),
69            trace_id,
70            kind,
71            message,
72        }
73    }
74
75    pub(crate) fn upcast(self) -> Envelope {
76        Envelope {
77            created_time: self.created_time,
78            trace_id: self.trace_id,
79            kind: self.kind,
80            message: AnyMessage::new(self.message),
81        }
82    }
83
84    // TODO: make `pub` for regular messages.
85    pub(crate) fn into_message(self) -> M {
86        self.message
87    }
88}
89
90impl Envelope {
91    #[inline]
92    pub fn is<M: Message>(&self) -> bool {
93        self.message.is::<M>()
94    }
95
96    pub(crate) fn do_downcast<M: Message>(self) -> Envelope<M> {
97        let message = self.message.downcast::<M>().expect("cannot downcast");
98        Envelope {
99            created_time: self.created_time,
100            trace_id: self.trace_id,
101            kind: self.kind,
102            message,
103        }
104    }
105
106    // XXX: why does `Envelope` know about `AddressBook`?
107    // TODO: avoid `None` here?
108    pub(crate) fn duplicate(&self, book: &AddressBook) -> Option<Self> {
109        Some(Self {
110            created_time: self.created_time,
111            trace_id: self.trace_id,
112            kind: match &self.kind {
113                MessageKind::Regular { sender } => MessageKind::Regular { sender: *sender },
114                MessageKind::RequestAny(token) => {
115                    let object = book.get(token.sender)?;
116                    let token = object.as_actor()?.request_table().clone_token(token)?;
117                    MessageKind::RequestAny(token)
118                }
119                MessageKind::RequestAll(token) => {
120                    let object = book.get(token.sender)?;
121                    let token = object.as_actor()?.request_table().clone_token(token)?;
122                    MessageKind::RequestAll(token)
123                }
124                MessageKind::Response { sender, request_id } => MessageKind::Response {
125                    sender: *sender,
126                    request_id: *request_id,
127                },
128            },
129            message: self.message.clone(),
130        })
131    }
132
133    pub(crate) fn set_message<M: Message>(&mut self, message: M) {
134        self.message = AnyMessage::new(message);
135    }
136}
137
138// Extra traits to support both owned and borrowed usages of `msg!(..)`.
139
140pub trait EnvelopeOwned {
141    fn unpack_regular(self) -> AnyMessage;
142    fn unpack_request<T>(self) -> (AnyMessage, ResponseToken<T>);
143}
144
145pub trait EnvelopeBorrowed {
146    fn unpack_regular(&self) -> &AnyMessage;
147}
148
149impl EnvelopeOwned for Envelope {
150    #[inline]
151    fn unpack_regular(self) -> AnyMessage {
152        self.message
153    }
154
155    #[inline]
156    fn unpack_request<T>(self) -> (AnyMessage, ResponseToken<T>) {
157        match self.kind {
158            MessageKind::RequestAny(token) => (self.message, token.into_typed()),
159            MessageKind::RequestAll(token) => (self.message, token.into_typed()),
160            _ => unreachable!(),
161        }
162    }
163}
164
165impl EnvelopeBorrowed for Envelope {
166    #[inline]
167    fn unpack_regular(&self) -> &AnyMessage {
168        &self.message
169    }
170}
171
172pub trait AnyMessageOwned {
173    fn downcast2<M: Message>(self) -> M;
174}
175
176pub trait AnyMessageBorrowed {
177    fn downcast2<M: Message>(&self) -> &M;
178}
179
180impl AnyMessageOwned for AnyMessage {
181    #[inline]
182    #[track_caller]
183    fn downcast2<M: Message>(self) -> M {
184        match self.downcast::<M>() {
185            Ok(message) => message,
186            Err(message) => panic!("unexpected message: {message:?}"),
187        }
188    }
189}
190
191impl AnyMessageBorrowed for AnyMessage {
192    #[inline]
193    #[track_caller]
194    fn downcast2<M: Message>(&self) -> &M {
195        ward!(
196            self.downcast_ref::<M>(),
197            panic!("unexpected message: {self:?}")
198        )
199    }
200}