1use std::collections::HashMap;
4use std::hash::{Hash, Hasher};
5
6use num_bigint::BigInt;
7use num_traits::{ToPrimitive, Zero};
8
9use crate::Pid;
10
11#[derive(Clone)]
13pub enum Value {
14 Int(i64),
16 BigInt(BigInt),
18 Float(f64),
20 Pid(Pid),
22 Ref(u64),
24 String(String),
26 Binary(Vec<u8>),
28 Atom(String),
30 Tuple(Vec<Value>),
32 List(Vec<Value>),
34 Map(HashMap<Value, Value>),
36 Fun {
38 module: String,
39 function: String,
40 arity: u8,
41 },
42 Closure {
44 module: String,
45 function: String,
46 arity: u8,
47 captured: Vec<Value>,
48 },
49 None,
51}
52
53impl Value {
54 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 pub fn as_binary(&self) -> Option<&[u8]> {
65 match self {
66 Value::Binary(bytes) => Some(bytes),
67 _ => None,
68 }
69 }
70
71 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 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 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 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 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 (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 {}