1use std::fmt;
2use std::sync::Arc;
3
4pub const TAG_SYS_DOWN: u16 = 0xFF01;
6pub const TAG_SYS_EXIT: u16 = 0xFF02;
8
9#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
27pub struct Message {
28 pub sender: u64,
30 pub reply_cap: u64,
32 pub request_id: u64,
34 pub tag: u16,
36 pub payload: u64,
38}
39
40impl Message {
41 pub const fn new(sender: u64, request_id: u64, tag: u16, payload: u64) -> Self {
45 Self {
46 sender,
47 reply_cap: 0,
48 request_id,
49 tag,
50 payload,
51 }
52 }
53
54 pub const fn request(request_id: u64, tag: u16, payload: u64) -> Self {
56 Self::new(0, request_id, tag, payload)
57 }
58
59 pub fn reply_to(req: &Self, tag: u16, payload: u64) -> Self {
61 Self::new(0, req.request_id, tag, payload)
62 }
63
64 pub const fn down(monitor: u64, target_flow: u64, reason: u64) -> Self {
69 Self {
70 sender: target_flow,
71 reply_cap: 0,
72 request_id: monitor,
73 tag: TAG_SYS_DOWN,
74 payload: reason,
75 }
76 }
77
78 pub const fn linked_exit(target_flow: u64, reason: u64) -> Self {
83 Self {
84 sender: target_flow,
85 reply_cap: 0,
86 request_id: 0,
87 tag: TAG_SYS_EXIT,
88 payload: reason,
89 }
90 }
91
92 #[inline]
93 pub const fn is_down(self) -> bool {
94 self.tag == TAG_SYS_DOWN
95 }
96
97 #[inline]
98 pub const fn is_exit(self) -> bool {
99 self.tag == TAG_SYS_EXIT
100 }
101
102 #[inline]
104 pub(crate) fn authenticate(mut self, sender: u64, reply_cap: u64) -> Self {
105 self.sender = sender;
106 self.reply_cap = reply_cap;
107 self
108 }
109}
110
111impl fmt::Display for Message {
112 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113 write!(
114 f,
115 "msg{{from=flow#{}, reply=cap#{}, id={}, tag={}, payload={}}}",
116 self.sender, self.reply_cap, self.request_id, self.tag, self.payload
117 )
118 }
119}
120
121#[derive(Clone, Debug, PartialEq)]
130pub enum Value {
131 Unit,
132 Bool(bool),
133 Int(i64),
134 Float(f64),
135 Pid(u64),
137 Message(Message),
139 Cap(u64),
141 Str(Arc<str>),
143 Bytes(Arc<[u8]>),
145}
146
147impl Value {
148 #[inline]
150 pub fn str(s: impl AsRef<str>) -> Self {
151 Value::Str(Arc::from(s.as_ref()))
152 }
153
154 #[inline]
156 pub fn bytes(b: impl AsRef<[u8]>) -> Self {
157 Value::Bytes(Arc::from(b.as_ref()))
158 }
159
160 #[inline]
163 pub fn is_truthy(&self) -> bool {
164 match self {
165 Value::Unit | Value::Bool(false) | Value::Int(0) => false,
166 Value::Str(s) if s.is_empty() => false,
167 Value::Bytes(b) if b.is_empty() => false,
168 _ => true,
169 }
170 }
171
172 #[inline]
173 pub fn as_int(&self) -> Option<i64> {
174 match self {
175 Value::Int(i) => Some(*i),
176 Value::Bool(b) => Some(*b as i64),
177 _ => None,
178 }
179 }
180
181 #[inline]
182 pub fn as_pid(&self) -> Option<u64> {
183 match self {
184 Value::Pid(p) => Some(*p),
185 _ => None,
186 }
187 }
188
189 #[inline]
190 pub fn as_cap(&self) -> Option<u64> {
191 match self {
192 Value::Cap(c) => Some(*c),
193 _ => None,
194 }
195 }
196
197 #[inline]
198 pub fn as_message(&self) -> Option<Message> {
199 match self {
200 Value::Message(m) => Some(*m),
201 _ => None,
202 }
203 }
204
205 #[inline]
206 pub fn as_str(&self) -> Option<&str> {
207 match self {
208 Value::Str(s) => Some(s.as_ref()),
209 _ => None,
210 }
211 }
212
213 #[inline]
214 pub fn as_bytes(&self) -> Option<&[u8]> {
215 match self {
216 Value::Bytes(b) => Some(b.as_ref()),
217 Value::Str(s) => Some(s.as_bytes()),
218 _ => None,
219 }
220 }
221
222 #[inline]
238 pub fn memory_size(&self) -> usize {
239 std::mem::size_of::<Self>() + self.heap_size()
240 }
241
242 #[inline]
245 pub fn heap_size(&self) -> usize {
246 match self {
247 Value::Str(s) => s.len(),
248 Value::Bytes(b) => b.len(),
249 Value::Unit
250 | Value::Bool(_)
251 | Value::Int(_)
252 | Value::Float(_)
253 | Value::Pid(_)
254 | Value::Message(_)
255 | Value::Cap(_) => 0,
256 }
257 }
258
259 pub fn type_name(&self) -> &'static str {
260 match self {
261 Value::Unit => "unit",
262 Value::Bool(_) => "bool",
263 Value::Int(_) => "int",
264 Value::Float(_) => "float",
265 Value::Pid(_) => "pid",
266 Value::Message(_) => "message",
267 Value::Cap(_) => "cap",
268 Value::Str(_) => "str",
269 Value::Bytes(_) => "bytes",
270 }
271 }
272}
273
274impl fmt::Display for Value {
275 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
276 match self {
277 Value::Unit => write!(f, "()"),
278 Value::Bool(b) => write!(f, "{b}"),
279 Value::Int(i) => write!(f, "{i}"),
280 Value::Float(x) => write!(f, "{x}"),
281 Value::Pid(p) => write!(f, "flow#{p}"),
282 Value::Message(m) => write!(f, "{m}"),
283 Value::Cap(c) => write!(f, "cap#{c}"),
284 Value::Str(s) => write!(f, "{s}"),
285 Value::Bytes(b) => write!(f, "bytes[{}]", b.len()),
286 }
287 }
288}
289
290impl From<i64> for Value {
291 fn from(v: i64) -> Self {
292 Value::Int(v)
293 }
294}
295impl From<bool> for Value {
296 fn from(v: bool) -> Self {
297 Value::Bool(v)
298 }
299}
300impl From<f64> for Value {
301 fn from(v: f64) -> Self {
302 Value::Float(v)
303 }
304}
305impl From<Message> for Value {
306 fn from(m: Message) -> Self {
307 Value::Message(m)
308 }
309}
310impl From<&str> for Value {
311 fn from(s: &str) -> Self {
312 Value::str(s)
313 }
314}
315impl From<String> for Value {
316 fn from(s: String) -> Self {
317 Value::Str(Arc::from(s))
318 }
319}
320impl From<&[u8]> for Value {
321 fn from(b: &[u8]) -> Self {
322 Value::bytes(b)
323 }
324}
325impl From<Vec<u8>> for Value {
326 fn from(b: Vec<u8>) -> Self {
327 Value::Bytes(Arc::from(b))
328 }
329}
330
331#[cfg(test)]
332mod tests {
333 use super::*;
334
335 #[test]
336 fn message_is_truthy_and_round_trips_helpers() {
337 let m = Message::new(7, 99, 10, 1);
338 let v = Value::Message(m);
339 assert!(v.is_truthy());
340 assert_eq!(v.as_message(), Some(m));
341 assert_eq!(v.type_name(), "message");
342 }
343
344 #[test]
345 fn authenticate_stamps_sender_and_reply_cap() {
346 let m = Message::new(999, 1, 2, 3).authenticate(42, 7);
347 assert_eq!(m.sender, 42);
348 assert_eq!(m.reply_cap, 7);
349 assert_eq!(m.request_id, 1);
350 }
351
352 #[test]
353 fn cap_is_truthy() {
354 assert!(Value::Cap(1).is_truthy());
355 assert_eq!(Value::Cap(3).as_cap(), Some(3));
356 }
357
358 #[test]
359 fn str_and_bytes_helpers() {
360 let s = Value::str("hi");
361 assert_eq!(s.as_str(), Some("hi"));
362 assert_eq!(s.type_name(), "str");
363 assert!(s.is_truthy());
364 assert!(!Value::str("").is_truthy());
365
366 let b = Value::bytes([1u8, 2, 3]);
367 assert_eq!(b.as_bytes(), Some(&[1, 2, 3][..]));
368 assert_eq!(b.type_name(), "bytes");
369 assert!(b.is_truthy());
370 assert!(!Value::bytes([]).is_truthy());
371
372 assert_eq!(s.as_bytes(), Some(b"hi".as_slice()));
374 }
375
376 #[test]
377 fn str_eq_compares_content() {
378 assert_eq!(Value::str("a"), Value::from("a".to_owned()));
379 assert_ne!(Value::str("a"), Value::str("b"));
380 assert_eq!(Value::bytes([9]), Value::from(vec![9u8]));
381 }
382}