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