logicaffeine_data/types.rs
1//! Core runtime type definitions.
2//!
3//! This module defines the primitive types used by LOGOS programs at runtime.
4//! These are type aliases that map LOGOS types to their Rust equivalents.
5//!
6//! ## Type Mappings
7//!
8//! | LOGOS Type | Rust Type | Description |
9//! |------------|-----------|-------------|
10//! | `Nat` | `u64` | Natural numbers (non-negative) |
11//! | `Int` | `i64` | Signed integers |
12//! | `Real` | `f64` | Floating-point numbers |
13//! | `Text` | `String` | UTF-8 strings |
14//! | `Bool` | `bool` | Boolean values |
15//! | `Unit` | `()` | The unit type |
16//! | `Char` | `char` | Unicode scalar values |
17//! | `Byte` | `u8` | Raw bytes |
18//! | `Seq<T>` | `Vec<T>` | Ordered sequences |
19//! | `Set<T>` | `HashSet<T>` | Unordered unique elements |
20//! | `Map<K,V>` | `HashMap<K,V>` | Key-value mappings |
21
22use std::hash::Hash;
23
24/// Non-negative integers. Maps to Peano `Nat` in the kernel.
25pub type Nat = u64;
26/// Signed integers.
27pub type Int = i64;
28/// IEEE 754 floating-point numbers.
29pub type Real = f64;
30/// UTF-8 encoded text strings.
31pub type Text = String;
32/// Boolean truth values.
33pub type Bool = bool;
34/// The unit type (single value).
35pub type Unit = ();
36/// Unicode scalar values.
37pub type Char = char;
38/// Raw bytes (0-255).
39pub type Byte = u8;
40
41/// Ordered sequences (lists).
42pub type Seq<T> = Vec<T>;
43
44/// Key-value mappings with hash-based lookup.
45pub type Map<K, V> = std::collections::HashMap<K, V>;
46
47/// Unordered collections of unique elements.
48pub type Set<T> = std::collections::HashSet<T>;
49
50/// Unified containment testing for all collection types.
51///
52/// This trait provides a consistent `logos_contains` method across Logos's
53/// collection types, abstracting over the different containment semantics
54/// of vectors (by value), sets (by membership), maps (by key), and
55/// strings (by substring or character).
56///
57/// # Implementations
58///
59/// - [`Vec<T>`]: Tests if the vector contains an element equal to the value
60/// - [`HashSet<T>`]: Tests if the element is a member of the set
61/// - [`HashMap<K, V>`]: Tests if a key exists in the map
62/// - [`String`]: Tests for substring (`&str`) or character (`char`) presence
63/// - [`ORSet<T, B>`]: Tests if the element is in the CRDT set
64///
65/// # Examples
66///
67/// ```
68/// use logicaffeine_data::LogosContains;
69///
70/// // Vector: contains by value equality
71/// let v = vec![1, 2, 3];
72/// assert!(v.logos_contains(&2));
73/// assert!(!v.logos_contains(&5));
74///
75/// // String: contains by substring
76/// let s = String::from("hello world");
77/// assert!(s.logos_contains(&"world"));
78///
79/// // String: contains by character
80/// assert!(s.logos_contains(&'o'));
81/// ```
82pub trait LogosContains<T> {
83 /// Check if this collection contains the given value.
84 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/// Dynamic value type for heterogeneous collections.
132///
133/// `Value` enables tuples and other heterogeneous data structures in Logos.
134/// It supports basic arithmetic between compatible types and provides
135/// runtime type coercion where sensible.
136///
137/// # Variants
138///
139/// - `Int(i64)` - Integer values
140/// - `Float(f64)` - Floating-point values
141/// - `Bool(bool)` - Boolean values
142/// - `Text(String)` - String values
143/// - `Char(char)` - Single character values
144/// - `Nothing` - Unit/null value
145///
146/// # Arithmetic
147///
148/// Arithmetic operations are supported between numeric types:
149/// - `Int op Int` → `Int`
150/// - `Float op Float` → `Float`
151/// - `Int op Float` or `Float op Int` → `Float` (promotion)
152/// - `Text + Text` → `Text` (concatenation)
153///
154/// # Panics
155///
156/// Arithmetic on incompatible variants panics at runtime.
157///
158/// # Examples
159///
160/// ```
161/// use logicaffeine_data::Value;
162///
163/// let a = Value::Int(10);
164/// let b = Value::Int(3);
165/// assert_eq!(a + b, Value::Int(13));
166///
167/// let x = Value::Float(2.5);
168/// let y = Value::Int(2);
169/// assert_eq!(x * y, Value::Float(5.0));
170/// ```
171#[derive(Clone, Debug, PartialEq)]
172pub enum Value {
173 /// Integer values.
174 Int(i64),
175 /// Floating-point values.
176 Float(f64),
177 /// Boolean values.
178 Bool(bool),
179 /// String values.
180 Text(String),
181 /// Single character values.
182 Char(char),
183 /// Unit/null value.
184 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
200// Conversion traits for Value
201impl 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
225/// Tuple type: Vec of heterogeneous Values (uses LogosIndex from indexing module)
226pub type Tuple = Vec<Value>;
227
228// NOTE: Showable impl for Value is in logicaffeine_system (io module)
229// This crate (logicaffeine_data) has NO IO dependencies.
230
231// Arithmetic operations for Value
232impl 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}