1use std::hash::Hash;
23
24pub type Nat = u64;
26pub type Int = i64;
28pub type Real = f64;
30pub type Text = String;
32pub type Bool = bool;
34pub type Unit = ();
36pub type Char = char;
38pub type Byte = u8;
40
41pub type Seq<T> = Vec<T>;
43
44pub type Map<K, V> = std::collections::HashMap<K, V>;
46
47pub type Set<T> = std::collections::HashSet<T>;
49
50pub trait LogosContains<T> {
83 fn logos_contains(&self, value: &T) -> bool;
85}
86
87impl<T: PartialEq> LogosContains<T> for Vec<T> {
88 fn logos_contains(&self, value: &T) -> bool {
89 self.contains(value)
90 }
91}
92
93impl<T: Eq + Hash> LogosContains<T> for std::collections::HashSet<T> {
94 fn logos_contains(&self, value: &T) -> bool {
95 self.contains(value)
96 }
97}
98
99impl<K: Eq + Hash, V> LogosContains<K> for std::collections::HashMap<K, V> {
100 fn logos_contains(&self, key: &K) -> bool {
101 self.contains_key(key)
102 }
103}
104
105impl LogosContains<&str> for String {
106 fn logos_contains(&self, value: &&str) -> bool {
107 self.contains(*value)
108 }
109}
110
111impl LogosContains<String> for String {
112 fn logos_contains(&self, value: &String) -> bool {
113 self.contains(value.as_str())
114 }
115}
116
117impl LogosContains<char> for String {
118 fn logos_contains(&self, value: &char) -> bool {
119 self.contains(*value)
120 }
121}
122
123impl<T: Eq + Hash + Clone, B: crate::crdt::SetBias> LogosContains<T>
124 for crate::crdt::ORSet<T, B>
125{
126 fn logos_contains(&self, value: &T) -> bool {
127 self.contains(value)
128 }
129}
130
131#[derive(Clone, Debug, PartialEq)]
172pub enum Value {
173 Int(i64),
175 Float(f64),
177 Bool(bool),
179 Text(String),
181 Char(char),
183 Nothing,
185}
186
187impl std::fmt::Display for Value {
188 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
189 match self {
190 Value::Int(n) => write!(f, "{}", n),
191 Value::Float(n) => write!(f, "{}", n),
192 Value::Bool(b) => write!(f, "{}", b),
193 Value::Text(s) => write!(f, "{}", s),
194 Value::Char(c) => write!(f, "{}", c),
195 Value::Nothing => write!(f, "nothing"),
196 }
197 }
198}
199
200impl From<i64> for Value {
202 fn from(n: i64) -> Self { Value::Int(n) }
203}
204
205impl From<f64> for Value {
206 fn from(n: f64) -> Self { Value::Float(n) }
207}
208
209impl From<bool> for Value {
210 fn from(b: bool) -> Self { Value::Bool(b) }
211}
212
213impl From<String> for Value {
214 fn from(s: String) -> Self { Value::Text(s) }
215}
216
217impl From<&str> for Value {
218 fn from(s: &str) -> Self { Value::Text(s.to_string()) }
219}
220
221impl From<char> for Value {
222 fn from(c: char) -> Self { Value::Char(c) }
223}
224
225pub type Tuple = Vec<Value>;
227
228impl std::ops::Add for Value {
233 type Output = Value;
234
235 fn add(self, other: Value) -> Value {
236 match (self, other) {
237 (Value::Int(a), Value::Int(b)) => Value::Int(a + b),
238 (Value::Float(a), Value::Float(b)) => Value::Float(a + b),
239 (Value::Int(a), Value::Float(b)) => Value::Float(a as f64 + b),
240 (Value::Float(a), Value::Int(b)) => Value::Float(a + b as f64),
241 (Value::Text(a), Value::Text(b)) => Value::Text(format!("{}{}", a, b)),
242 _ => panic!("Cannot add these value types"),
243 }
244 }
245}
246
247impl std::ops::Sub for Value {
248 type Output = Value;
249
250 fn sub(self, other: Value) -> Value {
251 match (self, other) {
252 (Value::Int(a), Value::Int(b)) => Value::Int(a - b),
253 (Value::Float(a), Value::Float(b)) => Value::Float(a - b),
254 (Value::Int(a), Value::Float(b)) => Value::Float(a as f64 - b),
255 (Value::Float(a), Value::Int(b)) => Value::Float(a - b as f64),
256 _ => panic!("Cannot subtract these value types"),
257 }
258 }
259}
260
261impl std::ops::Mul for Value {
262 type Output = Value;
263
264 fn mul(self, other: Value) -> Value {
265 match (self, other) {
266 (Value::Int(a), Value::Int(b)) => Value::Int(a * b),
267 (Value::Float(a), Value::Float(b)) => Value::Float(a * b),
268 (Value::Int(a), Value::Float(b)) => Value::Float(a as f64 * b),
269 (Value::Float(a), Value::Int(b)) => Value::Float(a * b as f64),
270 _ => panic!("Cannot multiply these value types"),
271 }
272 }
273}
274
275impl std::ops::Div for Value {
276 type Output = Value;
277
278 fn div(self, other: Value) -> Value {
279 match (self, other) {
280 (Value::Int(a), Value::Int(b)) => Value::Int(a / b),
281 (Value::Float(a), Value::Float(b)) => Value::Float(a / b),
282 (Value::Int(a), Value::Float(b)) => Value::Float(a as f64 / b),
283 (Value::Float(a), Value::Int(b)) => Value::Float(a / b as f64),
284 _ => panic!("Cannot divide these value types"),
285 }
286 }
287}
288
289#[cfg(test)]
290mod tests {
291 use super::*;
292
293 #[test]
294 fn value_int_arithmetic() {
295 assert_eq!(Value::Int(10) + Value::Int(3), Value::Int(13));
296 assert_eq!(Value::Int(10) - Value::Int(3), Value::Int(7));
297 assert_eq!(Value::Int(10) * Value::Int(3), Value::Int(30));
298 assert_eq!(Value::Int(10) / Value::Int(3), Value::Int(3));
299 }
300
301 #[test]
302 fn value_float_arithmetic() {
303 assert_eq!(Value::Float(2.5) + Value::Float(1.5), Value::Float(4.0));
304 assert_eq!(Value::Float(5.0) - Value::Float(1.5), Value::Float(3.5));
305 assert_eq!(Value::Float(2.0) * Value::Float(3.0), Value::Float(6.0));
306 assert_eq!(Value::Float(7.0) / Value::Float(2.0), Value::Float(3.5));
307 }
308
309 #[test]
310 fn value_cross_type_promotion() {
311 assert_eq!(Value::Int(2) + Value::Float(1.5), Value::Float(3.5));
312 assert_eq!(Value::Float(2.5) + Value::Int(2), Value::Float(4.5));
313 assert_eq!(Value::Int(3) * Value::Float(2.0), Value::Float(6.0));
314 assert_eq!(Value::Float(6.0) / Value::Int(2), Value::Float(3.0));
315 }
316
317 #[test]
318 fn value_text_concat() {
319 assert_eq!(
320 Value::Text("hello".to_string()) + Value::Text(" world".to_string()),
321 Value::Text("hello world".to_string())
322 );
323 }
324
325 #[test]
326 #[should_panic(expected = "divide by zero")]
327 fn value_div_by_zero_panics() {
328 let _ = Value::Int(1) / Value::Int(0);
329 }
330
331 #[test]
332 #[should_panic(expected = "Cannot add")]
333 fn value_incompatible_types_panic() {
334 let _ = Value::Bool(true) + Value::Int(1);
335 }
336
337 #[test]
338 fn value_display() {
339 assert_eq!(format!("{}", Value::Int(42)), "42");
340 assert_eq!(format!("{}", Value::Float(3.14)), "3.14");
341 assert_eq!(format!("{}", Value::Bool(true)), "true");
342 assert_eq!(format!("{}", Value::Text("hi".to_string())), "hi");
343 assert_eq!(format!("{}", Value::Char('a')), "a");
344 assert_eq!(format!("{}", Value::Nothing), "nothing");
345 }
346
347 #[test]
348 fn value_from_conversions() {
349 assert_eq!(Value::from(42i64), Value::Int(42));
350 assert_eq!(Value::from(3.14f64), Value::Float(3.14));
351 assert_eq!(Value::from(true), Value::Bool(true));
352 assert_eq!(Value::from("hello"), Value::Text("hello".to_string()));
353 assert_eq!(Value::from("hello".to_string()), Value::Text("hello".to_string()));
354 assert_eq!(Value::from('x'), Value::Char('x'));
355 }
356}