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