1use std::fmt;
2use std::sync::Arc;
3
4#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
22pub struct Message {
23 pub sender: u64,
25 pub reply_cap: u64,
27 pub request_id: u64,
29 pub tag: u16,
31 pub payload: u64,
33}
34
35impl Message {
36 pub const fn new(sender: u64, request_id: u64, tag: u16, payload: u64) -> Self {
40 Self {
41 sender,
42 reply_cap: 0,
43 request_id,
44 tag,
45 payload,
46 }
47 }
48
49 #[inline]
51 pub(crate) fn authenticate(mut self, sender: u64, reply_cap: u64) -> Self {
52 self.sender = sender;
53 self.reply_cap = reply_cap;
54 self
55 }
56}
57
58impl fmt::Display for Message {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 write!(
61 f,
62 "msg{{from=flow#{}, reply=cap#{}, id={}, tag={}, payload={}}}",
63 self.sender, self.reply_cap, self.request_id, self.tag, self.payload
64 )
65 }
66}
67
68#[derive(Clone, Debug, PartialEq)]
77pub enum Value {
78 Unit,
79 Bool(bool),
80 Int(i64),
81 Float(f64),
82 Pid(u64),
84 Message(Message),
86 Cap(u64),
88 Str(Arc<str>),
90 Bytes(Arc<[u8]>),
92}
93
94impl Value {
95 #[inline]
97 pub fn str(s: impl AsRef<str>) -> Self {
98 Value::Str(Arc::from(s.as_ref()))
99 }
100
101 #[inline]
103 pub fn bytes(b: impl AsRef<[u8]>) -> Self {
104 Value::Bytes(Arc::from(b.as_ref()))
105 }
106
107 #[inline]
110 pub fn is_truthy(&self) -> bool {
111 match self {
112 Value::Unit | Value::Bool(false) | Value::Int(0) => false,
113 Value::Str(s) if s.is_empty() => false,
114 Value::Bytes(b) if b.is_empty() => false,
115 _ => true,
116 }
117 }
118
119 #[inline]
120 pub fn as_int(&self) -> Option<i64> {
121 match self {
122 Value::Int(i) => Some(*i),
123 Value::Bool(b) => Some(*b as i64),
124 _ => None,
125 }
126 }
127
128 #[inline]
129 pub fn as_pid(&self) -> Option<u64> {
130 match self {
131 Value::Pid(p) => Some(*p),
132 _ => None,
133 }
134 }
135
136 #[inline]
137 pub fn as_cap(&self) -> Option<u64> {
138 match self {
139 Value::Cap(c) => Some(*c),
140 _ => None,
141 }
142 }
143
144 #[inline]
145 pub fn as_message(&self) -> Option<Message> {
146 match self {
147 Value::Message(m) => Some(*m),
148 _ => None,
149 }
150 }
151
152 #[inline]
153 pub fn as_str(&self) -> Option<&str> {
154 match self {
155 Value::Str(s) => Some(s.as_ref()),
156 _ => None,
157 }
158 }
159
160 #[inline]
161 pub fn as_bytes(&self) -> Option<&[u8]> {
162 match self {
163 Value::Bytes(b) => Some(b.as_ref()),
164 Value::Str(s) => Some(s.as_bytes()),
165 _ => None,
166 }
167 }
168
169 #[inline]
185 pub fn memory_size(&self) -> usize {
186 std::mem::size_of::<Self>() + self.heap_size()
187 }
188
189 #[inline]
192 pub fn heap_size(&self) -> usize {
193 match self {
194 Value::Str(s) => s.len(),
195 Value::Bytes(b) => b.len(),
196 Value::Unit
197 | Value::Bool(_)
198 | Value::Int(_)
199 | Value::Float(_)
200 | Value::Pid(_)
201 | Value::Message(_)
202 | Value::Cap(_) => 0,
203 }
204 }
205
206 pub fn type_name(&self) -> &'static str {
207 match self {
208 Value::Unit => "unit",
209 Value::Bool(_) => "bool",
210 Value::Int(_) => "int",
211 Value::Float(_) => "float",
212 Value::Pid(_) => "pid",
213 Value::Message(_) => "message",
214 Value::Cap(_) => "cap",
215 Value::Str(_) => "str",
216 Value::Bytes(_) => "bytes",
217 }
218 }
219}
220
221impl fmt::Display for Value {
222 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
223 match self {
224 Value::Unit => write!(f, "()"),
225 Value::Bool(b) => write!(f, "{b}"),
226 Value::Int(i) => write!(f, "{i}"),
227 Value::Float(x) => write!(f, "{x}"),
228 Value::Pid(p) => write!(f, "flow#{p}"),
229 Value::Message(m) => write!(f, "{m}"),
230 Value::Cap(c) => write!(f, "cap#{c}"),
231 Value::Str(s) => write!(f, "{s}"),
232 Value::Bytes(b) => write!(f, "bytes[{}]", b.len()),
233 }
234 }
235}
236
237impl From<i64> for Value {
238 fn from(v: i64) -> Self {
239 Value::Int(v)
240 }
241}
242impl From<bool> for Value {
243 fn from(v: bool) -> Self {
244 Value::Bool(v)
245 }
246}
247impl From<f64> for Value {
248 fn from(v: f64) -> Self {
249 Value::Float(v)
250 }
251}
252impl From<Message> for Value {
253 fn from(m: Message) -> Self {
254 Value::Message(m)
255 }
256}
257impl From<&str> for Value {
258 fn from(s: &str) -> Self {
259 Value::str(s)
260 }
261}
262impl From<String> for Value {
263 fn from(s: String) -> Self {
264 Value::Str(Arc::from(s))
265 }
266}
267impl From<&[u8]> for Value {
268 fn from(b: &[u8]) -> Self {
269 Value::bytes(b)
270 }
271}
272impl From<Vec<u8>> for Value {
273 fn from(b: Vec<u8>) -> Self {
274 Value::Bytes(Arc::from(b))
275 }
276}
277
278#[cfg(test)]
279mod tests {
280 use super::*;
281
282 #[test]
283 fn message_is_truthy_and_round_trips_helpers() {
284 let m = Message::new(7, 99, 10, 1);
285 let v = Value::Message(m);
286 assert!(v.is_truthy());
287 assert_eq!(v.as_message(), Some(m));
288 assert_eq!(v.type_name(), "message");
289 }
290
291 #[test]
292 fn authenticate_stamps_sender_and_reply_cap() {
293 let m = Message::new(999, 1, 2, 3).authenticate(42, 7);
294 assert_eq!(m.sender, 42);
295 assert_eq!(m.reply_cap, 7);
296 assert_eq!(m.request_id, 1);
297 }
298
299 #[test]
300 fn cap_is_truthy() {
301 assert!(Value::Cap(1).is_truthy());
302 assert_eq!(Value::Cap(3).as_cap(), Some(3));
303 }
304
305 #[test]
306 fn str_and_bytes_helpers() {
307 let s = Value::str("hi");
308 assert_eq!(s.as_str(), Some("hi"));
309 assert_eq!(s.type_name(), "str");
310 assert!(s.is_truthy());
311 assert!(!Value::str("").is_truthy());
312
313 let b = Value::bytes([1u8, 2, 3]);
314 assert_eq!(b.as_bytes(), Some(&[1, 2, 3][..]));
315 assert_eq!(b.type_name(), "bytes");
316 assert!(b.is_truthy());
317 assert!(!Value::bytes([]).is_truthy());
318
319 assert_eq!(s.as_bytes(), Some(b"hi".as_slice()));
321 }
322
323 #[test]
324 fn str_eq_compares_content() {
325 assert_eq!(Value::str("a"), Value::from("a".to_owned()));
326 assert_ne!(Value::str("a"), Value::str("b"));
327 assert_eq!(Value::bytes([9]), Value::from(vec![9u8]));
328 }
329}