1use super::*;
2
3impl NanValue {
4 pub fn eq_in(self, other: Self, arena: &Arena) -> bool {
5 if self.0 == other.0 {
6 return true;
7 }
8 if self.is_float() != other.is_float() {
9 return false;
10 }
11 if self.is_float() {
12 return self.as_float() == other.as_float();
13 }
14 match (self.wrapper_parts(arena), other.wrapper_parts(arena)) {
15 (Some((self_kind, self_inner)), Some((other_kind, other_inner))) => {
16 return self_kind == other_kind && self_inner.eq_in(other_inner, arena);
17 }
18 (Some(_), None) | (None, Some(_)) => return false,
19 (None, None) => {}
20 }
21 if self.tag() == TAG_INLINE_VARIANT || other.tag() == TAG_INLINE_VARIANT {
23 let s_ctor = self.variant_ctor_id(arena);
24 let o_ctor = other.variant_ctor_id(arena);
25 return match (s_ctor, o_ctor) {
26 (Some(sc), Some(oc)) if sc == oc => {
27 if self.tag() == TAG_INLINE_VARIANT && other.tag() == TAG_INLINE_VARIANT {
29 self.inline_variant_inner()
30 .eq_in(other.inline_variant_inner(), arena)
31 } else {
32 let sf = self.variant_single_field(arena);
34 let of = other.variant_single_field(arena);
35 sf.eq_in(of, arena)
36 }
37 }
38 (Some(_), Some(_)) => false,
39 _ => false,
40 };
41 }
42 match (self.variant_parts(arena), other.variant_parts(arena)) {
43 (Some((st, sv, sf)), Some((ot, ov, of))) => {
44 return st == ot
45 && sv == ov
46 && sf.len() == of.len()
47 && sf.iter().zip(of).all(|(a, b)| a.eq_in(*b, arena));
48 }
49 (Some(_), None) | (None, Some(_)) => return false,
50 (None, None) => {}
51 }
52 if self.is_string() || other.is_string() {
53 return self.is_string()
54 && other.is_string()
55 && arena.get_string_value(self) == arena.get_string_value(other);
56 }
57 if self.tag() != other.tag() {
58 return false;
59 }
60 match self.tag() {
61 TAG_INT => self.as_int(arena) == other.as_int(arena),
62 TAG_IMMEDIATE | TAG_NONE => false,
63 TAG_STRING => arena.get_string_value(self) == arena.get_string_value(other),
64 TAG_LIST => {
65 let a_len = arena.list_len_value(self);
66 let b_len = arena.list_len_value(other);
67 a_len == b_len
68 && (0..a_len).all(|i| {
69 arena
70 .list_get_value(self, i)
71 .zip(arena.list_get_value(other, i))
72 .is_some_and(|(x, y)| x.eq_in(y, arena))
73 })
74 }
75 TAG_TUPLE => {
76 let a = arena.get_tuple(self.arena_index());
77 let b = arena.get_tuple(other.arena_index());
78 a.len() == b.len() && a.iter().zip(b).all(|(x, y)| x.eq_in(*y, arena))
79 }
80 TAG_VECTOR => {
81 let a = arena.vector_ref_value(self);
82 let b = arena.vector_ref_value(other);
83 a.len() == b.len() && a.iter().zip(b).all(|(x, y)| x.eq_in(*y, arena))
84 }
85 TAG_MAP => {
86 let a = arena.map_ref_value(self);
87 let b = arena.map_ref_value(other);
88 a.len() == b.len()
89 && a.iter()
90 .all(|(k, (_, v1))| b.get(k).is_some_and(|(_, v2)| v1.eq_in(*v2, arena)))
91 }
92 TAG_RECORD => {
93 let (ta, fa) = arena.get_record(self.arena_index());
94 let (tb, fb) = arena.get_record(other.arena_index());
95 ta == tb
96 && fa.len() == fb.len()
97 && fa.iter().zip(fb).all(|(a, b)| a.eq_in(*b, arena))
98 }
99 TAG_VARIANT | TAG_INLINE_VARIANT => {
100 unreachable!("variant comparison handled above")
101 }
102 TAG_SYMBOL => self.bits() == other.bits(),
103 _ => false,
104 }
105 }
106
107 pub fn hash_in<H: std::hash::Hasher>(self, state: &mut H, arena: &Arena) {
108 use std::hash::Hash;
109 if self.is_float() {
110 1u8.hash(state);
111 let f = self.as_float();
112 let bits = if f == 0.0 {
113 0.0f64.to_bits()
114 } else {
115 f.to_bits()
116 };
117 bits.hash(state);
118 return;
119 }
120 if let Some((kind, inner)) = self.wrapper_parts(arena) {
121 match kind {
122 WRAP_SOME => (TAG_SOME as u8).hash(state),
123 WRAP_OK => (TAG_OK as u8).hash(state),
124 WRAP_ERR => (TAG_ERR as u8).hash(state),
125 _ => (0xFFu8).hash(state),
126 }
127 inner.hash_in(state, arena);
128 return;
129 }
130 if let Some((tid, vid, inner)) = self.inline_variant_info(arena) {
131 (TAG_VARIANT as u8).hash(state);
132 tid.hash(state);
133 vid.hash(state);
134 inner.hash_in(state, arena);
135 return;
136 }
137 if let Some((tid, vid, fields)) = self.variant_parts(arena) {
138 (TAG_VARIANT as u8).hash(state);
139 tid.hash(state);
140 vid.hash(state);
141 for field in fields {
142 field.hash_in(state, arena);
143 }
144 return;
145 }
146 if self.is_string() {
147 (TAG_STRING as u8).hash(state);
148 arena.get_string_value(self).hash(state);
149 return;
150 }
151 let tag = self.tag();
152 (tag as u8).hash(state);
153 match tag {
154 TAG_INT => self.as_int(arena).hash(state),
155 TAG_IMMEDIATE => self.payload().hash(state),
156 TAG_NONE => 0u8.hash(state),
157 TAG_STRING => arena.get_string_value(self).hash(state),
158 TAG_LIST => {
159 arena.list_len_value(self).hash(state);
160 for item in arena.list_to_vec_value(self) {
161 item.hash_in(state, arena);
162 }
163 }
164 TAG_TUPLE => {
165 let items = arena.get_tuple(self.arena_index());
166 items.len().hash(state);
167 for item in items {
168 item.hash_in(state, arena);
169 }
170 }
171 TAG_VECTOR => {
172 let items = arena.vector_ref_value(self);
173 items.len().hash(state);
174 for item in items {
175 item.hash_in(state, arena);
176 }
177 }
178 TAG_RECORD => {
179 let (tid, fields) = arena.get_record(self.arena_index());
180 tid.hash(state);
181 for f in fields {
182 f.hash_in(state, arena);
183 }
184 }
185 TAG_VARIANT | TAG_INLINE_VARIANT => {
186 unreachable!("variant hashing handled above")
187 }
188 TAG_SYMBOL => self.bits().hash(state),
189 _ => self.0.hash(state),
190 }
191 }
192
193 pub fn repr(self, arena: &Arena) -> String {
194 if self.is_float() {
195 return self.as_float().to_string();
196 }
197 if let Some((kind, inner)) = self.wrapper_parts(arena) {
198 let ir = inner.repr_inner(arena);
199 return match kind {
200 WRAP_SOME => format!("Option.Some({})", ir),
201 WRAP_OK => format!("Result.Ok({})", ir),
202 WRAP_ERR => format!("Result.Err({})", ir),
203 _ => "??".into(),
204 };
205 }
206 if let Some((tid, vid, inner)) = self.inline_variant_info(arena) {
207 let vname = arena.get_variant_name(tid, vid);
208 return format!("{}({})", vname, inner.repr_inner(arena));
209 }
210 if let Some((tid, vid, fields)) = self.variant_parts(arena) {
211 let vname = arena.get_variant_name(tid, vid);
212 return if fields.is_empty() {
213 vname.to_string()
214 } else {
215 let parts: Vec<_> = fields.iter().map(|v| v.repr_inner(arena)).collect();
216 format!("{}({})", vname, parts.join(", "))
217 };
218 }
219 if self.is_string() {
220 return arena.get_string_value(self).to_string();
221 }
222 match self.tag() {
223 TAG_INT => self.as_int(arena).to_string(),
224 TAG_IMMEDIATE => match self.payload() {
225 IMM_FALSE => "false".into(),
226 IMM_TRUE => "true".into(),
227 IMM_UNIT => "Unit".into(),
228 _ => "??".into(),
229 },
230 TAG_NONE => "Option.None".into(),
231 TAG_STRING => arena.get_string_value(self).to_string(),
232 TAG_LIST => {
233 let parts: Vec<_> = arena
234 .list_to_vec_value(self)
235 .into_iter()
236 .map(|v| v.repr_inner(arena))
237 .collect();
238 format!("[{}]", parts.join(", "))
239 }
240 TAG_TUPLE => {
241 let items = arena.get_tuple(self.arena_index());
242 let parts: Vec<_> = items.iter().map(|v| v.repr_inner(arena)).collect();
243 format!("({})", parts.join(", "))
244 }
245 TAG_VECTOR => {
246 let items = arena.vector_ref_value(self);
247 let parts: Vec<_> = items.iter().map(|v| v.repr_inner(arena)).collect();
248 format!("Vector[{}]", parts.join(", "))
249 }
250 TAG_MAP => {
251 let map = arena.map_ref_value(self);
252 let mut pairs: Vec<_> = map
253 .values()
254 .map(|(k, v)| (k.repr_inner(arena), v.repr_inner(arena)))
255 .collect();
256 pairs.sort_by(|(a, _), (b, _)| a.cmp(b));
257 let parts: Vec<_> = pairs
258 .into_iter()
259 .map(|(k, v)| format!("{}: {}", k, v))
260 .collect();
261 format!("{{{}}}", parts.join(", "))
262 }
263 TAG_RECORD => {
264 let (tid, fields) = arena.get_record(self.arena_index());
265 let name = arena.get_type_name(tid);
266 let fnames = arena.get_field_names(tid);
267 let parts: Vec<_> = fnames
268 .iter()
269 .zip(fields)
270 .map(|(n, v)| format!("{}: {}", n, v.repr_inner(arena)))
271 .collect();
272 format!("{}({})", name, parts.join(", "))
273 }
274 TAG_VARIANT | TAG_INLINE_VARIANT => unreachable!("variant repr handled above"),
275 TAG_SYMBOL => match self.symbol_kind() {
276 SYMBOL_FN => format!("<fn {}>", arena.get_fn(self.symbol_index()).name),
277 SYMBOL_BUILTIN => format!("<builtin {}>", arena.get_builtin(self.symbol_index())),
278 SYMBOL_NAMESPACE => {
279 let (name, _) = arena.get_namespace(self.symbol_index());
280 format!("<type {}>", name)
281 }
282 SYMBOL_NULLARY_VARIANT => unreachable!("variant repr handled above"),
283 _ => "??".into(),
284 },
285 _ => "??".into(),
286 }
287 }
288
289 fn repr_inner(self, arena: &Arena) -> String {
290 if self.is_string() {
291 return format!("\"{}\"", arena.get_string_value(self));
292 }
293 self.repr(arena)
294 }
295
296 pub fn display(self, arena: &Arena) -> Option<String> {
297 if self.is_unit() {
298 None
299 } else {
300 Some(self.repr(arena))
301 }
302 }
303}