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