1use std::rc::Rc;
2use std::sync::atomic::Ordering;
3
4use super::VmValue;
5
6pub fn values_identical(a: &VmValue, b: &VmValue) -> bool {
11 match (a, b) {
12 (VmValue::List(x), VmValue::List(y)) => Rc::ptr_eq(x, y),
13 (VmValue::Dict(x), VmValue::Dict(y)) => Rc::ptr_eq(x, y),
14 (VmValue::Set(x), VmValue::Set(y)) => Rc::ptr_eq(x, y),
15 (VmValue::Closure(x), VmValue::Closure(y)) => Rc::ptr_eq(x, y),
16 (VmValue::String(x), VmValue::String(y)) => Rc::ptr_eq(x, y) || x == y,
17 (VmValue::Bytes(x), VmValue::Bytes(y)) => Rc::ptr_eq(x, y) || x == y,
18 (VmValue::BuiltinRef(x), VmValue::BuiltinRef(y)) => x == y,
19 (VmValue::Pair(x), VmValue::Pair(y)) => Rc::ptr_eq(x, y),
20 _ => values_equal(a, b),
22 }
23}
24
25pub fn value_identity_key(v: &VmValue) -> String {
30 match v {
31 VmValue::List(x) => format!("list@{:p}", Rc::as_ptr(x)),
32 VmValue::Dict(x) => format!("dict@{:p}", Rc::as_ptr(x)),
33 VmValue::Set(x) => format!("set@{:p}", Rc::as_ptr(x)),
34 VmValue::Closure(x) => format!("closure@{:p}", Rc::as_ptr(x)),
35 VmValue::String(x) => format!("string@{:p}", x.as_ptr()),
36 VmValue::Bytes(x) => format!("bytes@{:p}", Rc::as_ptr(x)),
37 VmValue::BuiltinRef(name) => format!("builtin@{name}"),
38 other => format!("{}@{}", other.type_name(), other.display()),
39 }
40}
41
42pub fn value_structural_hash_key(v: &VmValue) -> String {
48 let mut out = String::new();
49 write_structural_hash_key(v, &mut out);
50 out
51}
52
53fn write_structural_hash_key(v: &VmValue, out: &mut String) {
57 match v {
58 VmValue::Nil => out.push('N'),
59 VmValue::Bool(b) => {
60 out.push(if *b { 'T' } else { 'F' });
61 }
62 VmValue::Int(n) => {
63 out.push('i');
64 out.push_str(&n.to_string());
65 out.push(';');
66 }
67 VmValue::Float(n) => {
68 out.push('f');
69 out.push_str(&n.to_bits().to_string());
70 out.push(';');
71 }
72 VmValue::String(s) => {
73 out.push('s');
75 out.push_str(&s.len().to_string());
76 out.push(':');
77 out.push_str(s);
78 }
79 VmValue::Bytes(bytes) => {
80 out.push('b');
81 for byte in bytes.iter() {
82 out.push_str(&format!("{byte:02x}"));
83 }
84 out.push(';');
85 }
86 VmValue::Duration(ms) => {
87 out.push('d');
88 out.push_str(&ms.to_string());
89 out.push(';');
90 }
91 VmValue::List(items) => {
92 out.push('L');
93 for item in items.iter() {
94 write_structural_hash_key(item, out);
95 out.push(',');
96 }
97 out.push(']');
98 }
99 VmValue::Dict(map) => {
100 out.push('D');
101 for (k, v) in map.iter() {
102 out.push_str(&k.len().to_string());
104 out.push(':');
105 out.push_str(k);
106 out.push('=');
107 write_structural_hash_key(v, out);
108 out.push(',');
109 }
110 out.push('}');
111 }
112 VmValue::Set(items) => {
113 let mut keys: Vec<String> = items.iter().map(value_structural_hash_key).collect();
115 keys.sort();
116 out.push('S');
117 for k in &keys {
118 out.push_str(k);
119 out.push(',');
120 }
121 out.push('}');
122 }
123 other => {
124 let tn = other.type_name();
125 out.push('o');
126 out.push_str(&tn.len().to_string());
127 out.push(':');
128 out.push_str(tn);
129 let d = other.display();
130 out.push_str(&d.len().to_string());
131 out.push(':');
132 out.push_str(&d);
133 }
134 }
135}
136
137pub fn values_equal(a: &VmValue, b: &VmValue) -> bool {
138 match (a, b) {
139 (VmValue::Int(x), VmValue::Int(y)) => x == y,
140 (VmValue::Float(x), VmValue::Float(y)) => x == y,
141 (VmValue::String(x), VmValue::String(y)) => x == y,
142 (VmValue::Bytes(x), VmValue::Bytes(y)) => x == y,
143 (VmValue::Bool(x), VmValue::Bool(y)) => x == y,
144 (VmValue::Nil, VmValue::Nil) => true,
145 (VmValue::Int(x), VmValue::Float(y)) => (*x as f64) == *y,
146 (VmValue::Float(x), VmValue::Int(y)) => *x == (*y as f64),
147 (VmValue::TaskHandle(a), VmValue::TaskHandle(b)) => a == b,
148 (VmValue::Channel(_), VmValue::Channel(_)) => false, (VmValue::Atomic(a), VmValue::Atomic(b)) => {
150 a.value.load(Ordering::SeqCst) == b.value.load(Ordering::SeqCst)
151 }
152 (VmValue::List(a), VmValue::List(b)) => {
153 a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| values_equal(x, y))
154 }
155 (VmValue::Dict(a), VmValue::Dict(b)) => {
156 a.len() == b.len()
157 && a.iter()
158 .zip(b.iter())
159 .all(|((k1, v1), (k2, v2))| k1 == k2 && values_equal(v1, v2))
160 }
161 (
162 VmValue::EnumVariant {
163 enum_name: a_e,
164 variant: a_v,
165 fields: a_f,
166 },
167 VmValue::EnumVariant {
168 enum_name: b_e,
169 variant: b_v,
170 fields: b_f,
171 },
172 ) => {
173 a_e == b_e
174 && a_v == b_v
175 && a_f.len() == b_f.len()
176 && a_f.iter().zip(b_f.iter()).all(|(x, y)| values_equal(x, y))
177 }
178 (
179 VmValue::StructInstance {
180 struct_name: a_s,
181 fields: a_f,
182 },
183 VmValue::StructInstance {
184 struct_name: b_s,
185 fields: b_f,
186 },
187 ) => {
188 a_s == b_s
189 && a_f.len() == b_f.len()
190 && a_f
191 .iter()
192 .zip(b_f.iter())
193 .all(|((k1, v1), (k2, v2))| k1 == k2 && values_equal(v1, v2))
194 }
195 (VmValue::Set(a), VmValue::Set(b)) => {
196 a.len() == b.len() && a.iter().all(|x| b.iter().any(|y| values_equal(x, y)))
197 }
198 (VmValue::Generator(_), VmValue::Generator(_)) => false, (VmValue::Range(a), VmValue::Range(b)) => {
200 a.start == b.start && a.end == b.end && a.inclusive == b.inclusive
201 }
202 (VmValue::Iter(a), VmValue::Iter(b)) => Rc::ptr_eq(a, b),
203 (VmValue::Pair(a), VmValue::Pair(b)) => {
204 values_equal(&a.0, &b.0) && values_equal(&a.1, &b.1)
205 }
206 _ => false,
207 }
208}
209
210pub fn compare_values(a: &VmValue, b: &VmValue) -> i32 {
211 match (a, b) {
212 (VmValue::Int(x), VmValue::Int(y)) => x.cmp(y) as i32,
213 (VmValue::Float(x), VmValue::Float(y)) => {
214 if x < y {
215 -1
216 } else if x > y {
217 1
218 } else {
219 0
220 }
221 }
222 (VmValue::Int(x), VmValue::Float(y)) => {
223 let x = *x as f64;
224 if x < *y {
225 -1
226 } else if x > *y {
227 1
228 } else {
229 0
230 }
231 }
232 (VmValue::Float(x), VmValue::Int(y)) => {
233 let y = *y as f64;
234 if *x < y {
235 -1
236 } else if *x > y {
237 1
238 } else {
239 0
240 }
241 }
242 (VmValue::String(x), VmValue::String(y)) => x.cmp(y) as i32,
243 (VmValue::Pair(x), VmValue::Pair(y)) => {
244 let c = compare_values(&x.0, &y.0);
245 if c != 0 {
246 c
247 } else {
248 compare_values(&x.1, &y.1)
249 }
250 }
251 _ => 0,
252 }
253}