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