1use std::{borrow::Cow, fmt, sync::Arc};
2
3use erased_serde::Serialize as ErasedSerialize;
4use serde::Serialize;
5use smallbox::{smallbox, SmallBox};
6
7use elfo_utils::time::SystemTime;
8
9use super::{extract_name::extract_name, sequence_no::SequenceNo};
10use crate::{actor::ActorMeta, envelope, scope, thread::ThreadId, tracing::TraceId, Message};
11
12#[doc(hidden)]
15#[instability::unstable]
16pub struct Dump {
17 pub meta: Arc<ActorMeta>,
18 pub sequence_no: SequenceNo,
19 pub timestamp: SystemTime,
20 pub trace_id: TraceId,
21 pub thread_id: ThreadId,
22 pub direction: Direction,
23 pub message_name: MessageName,
24 pub message_protocol: &'static str,
25 pub message_kind: MessageKind,
26 pub message: ErasedMessage,
27}
28
29#[doc(hidden)]
30#[instability::unstable]
31pub type ErasedMessage = SmallBox<dyn ErasedSerialize + Send, [usize; 24]>;
32
33assert_impl_all!(Dump: Send);
34assert_eq_size!(Dump, [u8; 320]);
35
36impl Dump {
37 #[instability::unstable]
38 pub fn builder() -> DumpBuilder {
39 DumpBuilder {
40 timestamp: None,
41 direction: Direction::Out,
42 message_name: None,
43 message_protocol: "",
44 message_kind: MessageKind::Regular,
45 }
46 }
47
48 pub(crate) fn message(
49 message: &impl Message,
50 kind: &envelope::MessageKind,
51 direction: Direction,
52 ) -> Self {
53 Self::builder()
54 .direction(direction)
55 .message_name(message.name())
56 .message_protocol(message.protocol())
57 .message_kind(MessageKind::from_message_kind(kind))
58 .do_finish(message._erase())
59 }
60}
61
62#[instability::unstable]
65pub struct DumpBuilder {
66 timestamp: Option<SystemTime>,
67 direction: Direction,
68 message_name: Option<MessageName>,
69 message_protocol: &'static str,
70 message_kind: MessageKind,
71}
72
73impl DumpBuilder {
74 #[instability::unstable]
75 pub fn timestamp(&mut self, timestamp: impl Into<SystemTime>) -> &mut Self {
76 self.timestamp = Some(timestamp.into());
77 self
78 }
79
80 #[instability::unstable]
81 pub fn direction(&mut self, direction: Direction) -> &mut Self {
82 self.direction = direction;
83 self
84 }
85
86 #[instability::unstable]
87 pub fn message_name(&mut self, name: impl Into<MessageName>) -> &mut Self {
88 self.message_name = Some(name.into());
89 self
90 }
91
92 #[instability::unstable]
93 pub fn message_protocol(&mut self, protocol: &'static str) -> &mut Self {
94 self.message_protocol = protocol;
95 self
96 }
97
98 #[instability::unstable]
99 pub fn message_kind(&mut self, kind: MessageKind) -> &mut Self {
100 self.message_kind = kind;
101 self
102 }
103
104 #[instability::unstable]
105 pub fn finish<M>(&mut self, message: M) -> Dump
106 where
107 M: Serialize + Send + 'static,
108 {
109 if self.message_name.is_none() {
110 self.message_name = Some(extract_name(&message));
112 }
113
114 self.do_finish(smallbox!(message))
115 }
116
117 fn do_finish(&mut self, message: ErasedMessage) -> Dump {
118 let (meta, trace_id, sequence_no) = scope::with(|scope| {
119 (
120 scope.meta().clone(),
121 scope.trace_id(),
122 scope.dumping().next_sequence_no(),
123 )
124 });
125
126 Dump {
127 meta,
128 sequence_no,
129 timestamp: self.timestamp.unwrap_or_else(SystemTime::now),
130 trace_id,
131 thread_id: crate::thread::id(),
132 direction: self.direction,
133 message_name: self.message_name.take().unwrap_or_default(),
134 message_protocol: self.message_protocol,
135 message_kind: self.message_kind,
136 message,
137 }
138 }
139}
140
141#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
144#[instability::unstable]
145pub enum Direction {
146 In,
147 Out,
148}
149
150#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
153#[instability::unstable]
154pub struct MessageName(&'static str, Option<&'static str>);
155
156impl<'a> PartialEq<&'a str> for MessageName {
157 fn eq(&self, s: &&'a str) -> bool {
158 if let Some(variant) = self.1 {
159 s.split_once("::")
160 .is_some_and(|(n, v)| n == self.0 && v == variant)
161 } else {
162 self.0 == *s
163 }
164 }
165}
166
167impl PartialEq<MessageName> for &'_ str {
168 fn eq(&self, s: &MessageName) -> bool {
169 s == self
170 }
171}
172
173impl fmt::Display for MessageName {
174 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
175 f.write_str(self.0)?;
176
177 if let Some(variant) = self.1 {
178 f.write_str("::")?;
179 f.write_str(variant)?;
180 }
181
182 Ok(())
183 }
184}
185
186impl From<&'static str> for MessageName {
187 #[inline]
188 fn from(struct_name: &'static str) -> Self {
189 Self(struct_name, None)
190 }
191}
192
193impl From<(&'static str, &'static str)> for MessageName {
194 #[inline]
195 fn from((enum_name, variant): (&'static str, &'static str)) -> Self {
196 Self(enum_name, Some(variant))
197 }
198}
199
200impl From<MessageName> for Cow<'static, str> {
202 #[inline]
203 fn from(name: MessageName) -> Self {
204 Self::from(&name)
205 }
206}
207
208impl From<&MessageName> for Cow<'static, str> {
209 #[inline]
210 fn from(name: &MessageName) -> Self {
211 match name.1 {
212 Some(variant) => {
213 let mut string = String::with_capacity(name.0.len() + 2 + variant.len());
214 string.push_str(name.0);
215 string.push_str("::");
216 string.push_str(variant);
217 Self::Owned(string)
218 }
219 None => Self::Borrowed(name.0),
220 }
221 }
222}
223
224impl MessageName {
225 #[doc(hidden)]
226 #[instability::unstable]
227 pub fn to_str<'a>(&self, buffer: &'a mut String) -> &'a str {
228 if let Some(variant) = self.1 {
229 buffer.clear();
230 buffer.push_str(self.0);
231 buffer.push_str("::");
232 buffer.push_str(variant);
233 &buffer[..]
234 } else {
235 self.0
236 }
237 }
238}
239
240#[derive(Debug, Clone, Copy, PartialEq, Eq)]
243#[instability::unstable]
244pub enum MessageKind {
245 Regular,
246 Request(u64),
247 Response(u64),
248}
249
250impl MessageKind {
251 pub(crate) fn from_message_kind(kind: &crate::envelope::MessageKind) -> Self {
252 use slotmap::Key;
253
254 use crate::envelope::MessageKind as MK;
255
256 match kind {
257 MK::Regular { .. } => Self::Regular,
258 MK::RequestAny(token) | MK::RequestAll(token) => {
259 Self::Request(token.request_id().to_ffi())
260 }
261 MK::Response { request_id, .. } => Self::Response(request_id.data().as_ffi()),
262 }
263 }
264}
265
266#[test]
267fn message_name() {
268 assert_eq!(MessageName::from("A"), "A");
269 assert_ne!(MessageName::from("A"), "AB");
270 assert_eq!(MessageName::from(("A", "B")), "A::B");
271 assert_ne!(MessageName::from(("A", "B")), "AB::B");
272 assert_eq!("A", MessageName::from("A"), "A");
273
274 assert_eq!(Cow::from(MessageName::from("A")), "A");
275 assert_eq!(Cow::from(MessageName::from(("A", "B"))), "A::B");
276
277 let mut buf = String::new();
278 assert_eq!(MessageName::from("A").to_str(&mut buf), "A");
279 assert_eq!(MessageName::from(("A", "B")).to_str(&mut buf), "A::B");
280
281 assert_eq!(MessageName::from("A").to_string(), "A");
282 assert_eq!(MessageName::from(("A", "B")).to_string(), "A::B");
283}