surreal/
value.rs

1//! Runtime values stored in registers.
2
3use std::collections::HashMap;
4use std::hash::{Hash, Hasher};
5
6use num_bigint::BigInt;
7use num_traits::{ToPrimitive, Zero};
8
9use crate::Pid;
10
11/// Runtime value stored in registers
12#[derive(Clone)]
13pub enum Value {
14    /// Integer (fits in i64)
15    Int(i64),
16    /// Big integer (arbitrary precision)
17    BigInt(BigInt),
18    /// Floating-point number
19    Float(f64),
20    /// Process identifier
21    Pid(Pid),
22    /// Unique reference (for request/response correlation)
23    Ref(u64),
24    /// String (text data)
25    String(String),
26    /// Binary (raw byte array)
27    Binary(Vec<u8>),
28    /// Atom - an interned symbol
29    Atom(String),
30    /// Tuple - fixed-size container of values
31    Tuple(Vec<Value>),
32    /// List - variable-size linked list of values
33    List(Vec<Value>),
34    /// Map - key-value hash table (immutable, functional updates)
35    Map(HashMap<Value, Value>),
36    /// Function reference (module:function/arity)
37    Fun {
38        module: String,
39        function: String,
40        arity: u8,
41    },
42    /// Closure - function reference with captured environment
43    Closure {
44        module: String,
45        function: String,
46        arity: u8,
47        captured: Vec<Value>,
48    },
49    /// No value / uninitialized
50    None,
51}
52
53impl Value {
54    /// Try to extract an integer from this value
55    pub fn as_int(&self) -> Option<i64> {
56        match self {
57            Value::Int(n) => Some(*n),
58            Value::BigInt(n) => n.to_i64(),
59            _ => None,
60        }
61    }
62
63    /// Try to extract a binary from this value
64    pub fn as_binary(&self) -> Option<&[u8]> {
65        match self {
66            Value::Binary(bytes) => Some(bytes),
67            _ => None,
68        }
69    }
70
71    /// Convert to BigInt if this is any integer type
72    pub fn to_bigint(&self) -> Option<BigInt> {
73        match self {
74            Value::Int(n) => Some(BigInt::from(*n)),
75            Value::BigInt(n) => Some(n.clone()),
76            _ => None,
77        }
78    }
79
80    /// Create a Value from a BigInt, normalizing to Int if it fits
81    pub fn from_bigint(n: BigInt) -> Value {
82        if let Some(i) = n.to_i64() {
83            Value::Int(i)
84        } else {
85            Value::BigInt(n)
86        }
87    }
88
89    /// Check if this value is zero (for Int or BigInt)
90    pub fn is_zero(&self) -> bool {
91        match self {
92            Value::Int(0) => true,
93            Value::BigInt(n) => n.is_zero(),
94            _ => false,
95        }
96    }
97}
98
99impl std::fmt::Debug for Value {
100    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101        match self {
102            Value::Int(n) => write!(f, "{}", n),
103            Value::BigInt(n) => write!(f, "{}", n),
104            Value::Float(x) => write!(f, "{}", x),
105            Value::Pid(p) => write!(f, "Pid({})", p.0),
106            Value::Ref(r) => write!(f, "#Ref<{}>", r),
107            Value::String(s) => write!(f, "{:?}", s),
108            Value::Binary(bytes) => {
109                write!(f, "<<")?;
110                for (i, byte) in bytes.iter().enumerate() {
111                    if i > 0 {
112                        write!(f, ", ")?;
113                    }
114                    write!(f, "{}", byte)?;
115                }
116                write!(f, ">>")
117            }
118            Value::Atom(a) => write!(f, ":{}", a),
119            Value::Tuple(elements) => {
120                write!(f, "{{")?;
121                for (i, elem) in elements.iter().enumerate() {
122                    if i > 0 {
123                        write!(f, ", ")?;
124                    }
125                    write!(f, "{:?}", elem)?;
126                }
127                write!(f, "}}")
128            }
129            Value::List(elements) => {
130                write!(f, "[")?;
131                for (i, elem) in elements.iter().enumerate() {
132                    if i > 0 {
133                        write!(f, ", ")?;
134                    }
135                    write!(f, "{:?}", elem)?;
136                }
137                write!(f, "]")
138            }
139            Value::Map(entries) => {
140                write!(f, "%{{")?;
141                for (i, (k, v)) in entries.iter().enumerate() {
142                    if i > 0 {
143                        write!(f, ", ")?;
144                    }
145                    write!(f, "{:?} => {:?}", k, v)?;
146                }
147                write!(f, "}}")
148            }
149            Value::Fun {
150                module,
151                function,
152                arity,
153            } => write!(f, "fun {}:{}/{}", module, function, arity),
154            Value::Closure {
155                module,
156                function,
157                arity,
158                captured,
159            } => write!(
160                f,
161                "closure {}:{}/{} {:?}",
162                module, function, arity, captured
163            ),
164            Value::None => write!(f, "None"),
165        }
166    }
167}
168
169impl Hash for Value {
170    fn hash<H: Hasher>(&self, state: &mut H) {
171        std::mem::discriminant(self).hash(state);
172        match self {
173            Value::Int(n) => n.hash(state),
174            Value::BigInt(n) => {
175                // Hash the bytes of the BigInt
176                let (sign, bytes) = n.to_bytes_le();
177                sign.hash(state);
178                bytes.hash(state);
179            }
180            Value::Float(f) => f.to_bits().hash(state),
181            Value::Pid(p) => p.0.hash(state),
182            Value::Ref(r) => r.hash(state),
183            Value::String(s) => s.hash(state),
184            Value::Binary(bytes) => bytes.hash(state),
185            Value::Atom(a) => a.hash(state),
186            Value::Tuple(elems) => {
187                elems.len().hash(state);
188                for elem in elems {
189                    elem.hash(state);
190                }
191            }
192            Value::List(elems) => {
193                elems.len().hash(state);
194                for elem in elems {
195                    elem.hash(state);
196                }
197            }
198            Value::Map(entries) => {
199                // Hash map entries in a deterministic order
200                // by collecting and sorting by key hash
201                entries.len().hash(state);
202                let mut pairs: Vec<_> = entries.iter().collect();
203                pairs.sort_by(|a, b| {
204                    let mut ha = std::collections::hash_map::DefaultHasher::new();
205                    let mut hb = std::collections::hash_map::DefaultHasher::new();
206                    a.0.hash(&mut ha);
207                    b.0.hash(&mut hb);
208                    ha.finish().cmp(&hb.finish())
209                });
210                for (k, v) in pairs {
211                    k.hash(state);
212                    v.hash(state);
213                }
214            }
215            Value::Fun {
216                module,
217                function,
218                arity,
219            } => {
220                module.hash(state);
221                function.hash(state);
222                arity.hash(state);
223            }
224            Value::Closure {
225                module,
226                function,
227                arity,
228                captured,
229            } => {
230                module.hash(state);
231                function.hash(state);
232                arity.hash(state);
233                captured.len().hash(state);
234                for c in captured {
235                    c.hash(state);
236                }
237            }
238            Value::None => {}
239        }
240    }
241}
242
243impl From<i64> for Value {
244    fn from(n: i64) -> Self {
245        Value::Int(n)
246    }
247}
248
249impl From<f64> for Value {
250    fn from(f: f64) -> Self {
251        Value::Float(f)
252    }
253}
254
255impl PartialEq for Value {
256    fn eq(&self, other: &Self) -> bool {
257        match (self, other) {
258            (Value::Int(a), Value::Int(b)) => a == b,
259            (Value::BigInt(a), Value::BigInt(b)) => a == b,
260            // Cross-type Int/BigInt comparison
261            (Value::Int(a), Value::BigInt(b)) => BigInt::from(*a) == *b,
262            (Value::BigInt(a), Value::Int(b)) => *a == BigInt::from(*b),
263            (Value::Float(a), Value::Float(b)) => a.to_bits() == b.to_bits(),
264            (Value::Pid(a), Value::Pid(b)) => a == b,
265            (Value::Ref(a), Value::Ref(b)) => a == b,
266            (Value::String(a), Value::String(b)) => a == b,
267            (Value::Binary(a), Value::Binary(b)) => a == b,
268            (Value::Atom(a), Value::Atom(b)) => a == b,
269            (Value::Tuple(a), Value::Tuple(b)) => a == b,
270            (Value::List(a), Value::List(b)) => a == b,
271            (Value::Map(a), Value::Map(b)) => a == b,
272            (
273                Value::Fun {
274                    module: m1,
275                    function: f1,
276                    arity: a1,
277                },
278                Value::Fun {
279                    module: m2,
280                    function: f2,
281                    arity: a2,
282                },
283            ) => m1 == m2 && f1 == f2 && a1 == a2,
284            (
285                Value::Closure {
286                    module: m1,
287                    function: f1,
288                    arity: a1,
289                    captured: c1,
290                },
291                Value::Closure {
292                    module: m2,
293                    function: f2,
294                    arity: a2,
295                    captured: c2,
296                },
297            ) => m1 == m2 && f1 == f2 && a1 == a2 && c1 == c2,
298            (Value::None, Value::None) => true,
299            _ => false,
300        }
301    }
302}
303
304impl Eq for Value {}