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 pub fn type_name(&self) -> &'static str {
170 match self {
171 Value::Unit => "unit",
172 Value::Bool(_) => "bool",
173 Value::Int(_) => "int",
174 Value::Float(_) => "float",
175 Value::Pid(_) => "pid",
176 Value::Message(_) => "message",
177 Value::Cap(_) => "cap",
178 Value::Str(_) => "str",
179 Value::Bytes(_) => "bytes",
180 }
181 }
182}
183
184impl fmt::Display for Value {
185 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186 match self {
187 Value::Unit => write!(f, "()"),
188 Value::Bool(b) => write!(f, "{b}"),
189 Value::Int(i) => write!(f, "{i}"),
190 Value::Float(x) => write!(f, "{x}"),
191 Value::Pid(p) => write!(f, "flow#{p}"),
192 Value::Message(m) => write!(f, "{m}"),
193 Value::Cap(c) => write!(f, "cap#{c}"),
194 Value::Str(s) => write!(f, "{s}"),
195 Value::Bytes(b) => write!(f, "bytes[{}]", b.len()),
196 }
197 }
198}
199
200impl From<i64> for Value {
201 fn from(v: i64) -> Self {
202 Value::Int(v)
203 }
204}
205impl From<bool> for Value {
206 fn from(v: bool) -> Self {
207 Value::Bool(v)
208 }
209}
210impl From<f64> for Value {
211 fn from(v: f64) -> Self {
212 Value::Float(v)
213 }
214}
215impl From<Message> for Value {
216 fn from(m: Message) -> Self {
217 Value::Message(m)
218 }
219}
220impl From<&str> for Value {
221 fn from(s: &str) -> Self {
222 Value::str(s)
223 }
224}
225impl From<String> for Value {
226 fn from(s: String) -> Self {
227 Value::Str(Arc::from(s))
228 }
229}
230impl From<&[u8]> for Value {
231 fn from(b: &[u8]) -> Self {
232 Value::bytes(b)
233 }
234}
235impl From<Vec<u8>> for Value {
236 fn from(b: Vec<u8>) -> Self {
237 Value::Bytes(Arc::from(b))
238 }
239}
240
241#[cfg(test)]
242mod tests {
243 use super::*;
244
245 #[test]
246 fn message_is_truthy_and_round_trips_helpers() {
247 let m = Message::new(7, 99, 10, 1);
248 let v = Value::Message(m);
249 assert!(v.is_truthy());
250 assert_eq!(v.as_message(), Some(m));
251 assert_eq!(v.type_name(), "message");
252 }
253
254 #[test]
255 fn authenticate_stamps_sender_and_reply_cap() {
256 let m = Message::new(999, 1, 2, 3).authenticate(42, 7);
257 assert_eq!(m.sender, 42);
258 assert_eq!(m.reply_cap, 7);
259 assert_eq!(m.request_id, 1);
260 }
261
262 #[test]
263 fn cap_is_truthy() {
264 assert!(Value::Cap(1).is_truthy());
265 assert_eq!(Value::Cap(3).as_cap(), Some(3));
266 }
267
268 #[test]
269 fn str_and_bytes_helpers() {
270 let s = Value::str("hi");
271 assert_eq!(s.as_str(), Some("hi"));
272 assert_eq!(s.type_name(), "str");
273 assert!(s.is_truthy());
274 assert!(!Value::str("").is_truthy());
275
276 let b = Value::bytes([1u8, 2, 3]);
277 assert_eq!(b.as_bytes(), Some(&[1, 2, 3][..]));
278 assert_eq!(b.type_name(), "bytes");
279 assert!(b.is_truthy());
280 assert!(!Value::bytes([]).is_truthy());
281
282 assert_eq!(s.as_bytes(), Some(b"hi".as_slice()));
284 }
285
286 #[test]
287 fn str_eq_compares_content() {
288 assert_eq!(Value::str("a"), Value::from("a".to_owned()));
289 assert_ne!(Value::str("a"), Value::str("b"));
290 assert_eq!(Value::bytes([9]), Value::from(vec![9u8]));
291 }
292}