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 if self.tag() != other.tag() {
15 return false;
16 }
17 match self.tag() {
18 TAG_INT => self.as_int(arena) == other.as_int(arena),
19 TAG_IMMEDIATE => false,
20 TAG_WRAPPER => {
21 self.wrapper_kind() == other.wrapper_kind() && {
22 let a = arena.get_boxed(self.wrapper_index());
23 let b = arena.get_boxed(other.wrapper_index());
24 a.eq_in(b, arena)
25 }
26 }
27 TAG_STRING => {
28 arena.get_string(self.arena_index()) == arena.get_string(other.arena_index())
29 }
30 TAG_LIST => {
31 let a_idx = self.arena_index();
32 let b_idx = other.arena_index();
33 arena.list_len(a_idx) == arena.list_len(b_idx)
34 && (0..arena.list_len(a_idx)).all(|i| {
35 arena
36 .list_get(a_idx, i)
37 .zip(arena.list_get(b_idx, i))
38 .is_some_and(|(x, y)| x.eq_in(y, arena))
39 })
40 }
41 TAG_TUPLE => {
42 let a = arena.get_tuple(self.arena_index());
43 let b = arena.get_tuple(other.arena_index());
44 a.len() == b.len() && a.iter().zip(b).all(|(x, y)| x.eq_in(*y, arena))
45 }
46 TAG_MAP => {
47 let a = arena.get_map(self.arena_index());
48 let b = arena.get_map(other.arena_index());
49 a.len() == b.len()
50 && a.iter()
51 .all(|(k, (_, v1))| b.get(k).is_some_and(|(_, v2)| v1.eq_in(*v2, arena)))
52 }
53 TAG_RECORD => {
54 let (ta, fa) = arena.get_record(self.arena_index());
55 let (tb, fb) = arena.get_record(other.arena_index());
56 ta == tb
57 && fa.len() == fb.len()
58 && fa.iter().zip(fb).all(|(a, b)| a.eq_in(*b, arena))
59 }
60 TAG_VARIANT => {
61 let (ta, va, fa) = arena.get_variant(self.arena_index());
62 let (tb, vb, fb) = arena.get_variant(other.arena_index());
63 ta == tb
64 && va == vb
65 && fa.len() == fb.len()
66 && fa.iter().zip(fb).all(|(a, b)| a.eq_in(*b, arena))
67 }
68 TAG_FN => self.arena_index() == other.arena_index(),
69 _ => false,
70 }
71 }
72
73 pub fn hash_in<H: std::hash::Hasher>(self, state: &mut H, arena: &Arena) {
74 use std::hash::Hash;
75 if self.is_float() {
76 1u8.hash(state);
77 let f = self.as_float();
78 let bits = if f == 0.0 {
79 0.0f64.to_bits()
80 } else {
81 f.to_bits()
82 };
83 bits.hash(state);
84 return;
85 }
86 let tag = self.tag();
87 (tag as u8).hash(state);
88 match tag {
89 TAG_INT => self.as_int(arena).hash(state),
90 TAG_IMMEDIATE => self.payload().hash(state),
91 TAG_WRAPPER => {
92 self.wrapper_kind().hash(state);
93 arena.get_boxed(self.wrapper_index()).hash_in(state, arena);
94 }
95 TAG_STRING => arena.get_string(self.arena_index()).hash(state),
96 TAG_LIST => {
97 let list_idx = self.arena_index();
98 arena.list_len(list_idx).hash(state);
99 for item in arena.list_to_vec(list_idx) {
100 item.hash_in(state, arena);
101 }
102 }
103 TAG_TUPLE => {
104 let items = arena.get_tuple(self.arena_index());
105 items.len().hash(state);
106 for item in items {
107 item.hash_in(state, arena);
108 }
109 }
110 TAG_RECORD => {
111 let (tid, fields) = arena.get_record(self.arena_index());
112 tid.hash(state);
113 for f in fields {
114 f.hash_in(state, arena);
115 }
116 }
117 TAG_VARIANT => {
118 let (tid, vid, fields) = arena.get_variant(self.arena_index());
119 tid.hash(state);
120 vid.hash(state);
121 for f in fields {
122 f.hash_in(state, arena);
123 }
124 }
125 _ => self.0.hash(state),
126 }
127 }
128
129 pub fn repr(self, arena: &Arena) -> String {
130 if self.is_float() {
131 return self.as_float().to_string();
132 }
133 match self.tag() {
134 TAG_INT => self.as_int(arena).to_string(),
135 TAG_IMMEDIATE => match self.payload() {
136 IMM_FALSE => "false".into(),
137 IMM_TRUE => "true".into(),
138 IMM_UNIT => "Unit".into(),
139 IMM_NONE => "Option.None".into(),
140 _ => "??".into(),
141 },
142 TAG_WRAPPER => {
143 let inner = arena.get_boxed(self.wrapper_index());
144 let ir = inner.repr_inner(arena);
145 match self.wrapper_kind() {
146 WRAP_SOME => format!("Option.Some({})", ir),
147 WRAP_OK => format!("Result.Ok({})", ir),
148 WRAP_ERR => format!("Result.Err({})", ir),
149 _ => "??".into(),
150 }
151 }
152 TAG_STRING => arena.get_string(self.arena_index()).to_string(),
153 TAG_LIST => {
154 let parts: Vec<_> = arena
155 .list_to_vec(self.arena_index())
156 .into_iter()
157 .map(|v| v.repr_inner(arena))
158 .collect();
159 format!("[{}]", parts.join(", "))
160 }
161 TAG_TUPLE => {
162 let items = arena.get_tuple(self.arena_index());
163 let parts: Vec<_> = items.iter().map(|v| v.repr_inner(arena)).collect();
164 format!("({})", parts.join(", "))
165 }
166 TAG_MAP => {
167 let map = arena.get_map(self.arena_index());
168 let mut pairs: Vec<_> = map
169 .values()
170 .map(|(k, v)| (k.repr_inner(arena), v.repr_inner(arena)))
171 .collect();
172 pairs.sort_by(|(a, _), (b, _)| a.cmp(b));
173 let parts: Vec<_> = pairs
174 .into_iter()
175 .map(|(k, v)| format!("{}: {}", k, v))
176 .collect();
177 format!("{{{}}}", parts.join(", "))
178 }
179 TAG_RECORD => {
180 let (tid, fields) = arena.get_record(self.arena_index());
181 let name = arena.get_type_name(tid);
182 let fnames = arena.get_field_names(tid);
183 let parts: Vec<_> = fnames
184 .iter()
185 .zip(fields)
186 .map(|(n, v)| format!("{}: {}", n, v.repr_inner(arena)))
187 .collect();
188 format!("{}({})", name, parts.join(", "))
189 }
190 TAG_VARIANT => {
191 let (tid, vid, fields) = arena.get_variant(self.arena_index());
192 let vname = arena.get_variant_name(tid, vid);
193 if fields.is_empty() {
194 vname.to_string()
195 } else {
196 let parts: Vec<_> = fields.iter().map(|v| v.repr_inner(arena)).collect();
197 format!("{}({})", vname, parts.join(", "))
198 }
199 }
200 TAG_FN => format!("<fn {}>", arena.get_fn(self.arena_index()).name),
201 TAG_BUILTIN => format!("<builtin {}>", arena.get_builtin(self.arena_index())),
202 TAG_NAMESPACE => {
203 let (name, _) = arena.get_namespace(self.arena_index());
204 format!("<type {}>", name)
205 }
206 _ => "??".into(),
207 }
208 }
209
210 fn repr_inner(self, arena: &Arena) -> String {
211 if self.is_string() {
212 return format!("\"{}\"", arena.get_string(self.arena_index()));
213 }
214 self.repr(arena)
215 }
216
217 pub fn display(self, arena: &Arena) -> Option<String> {
218 if self.is_unit() {
219 None
220 } else {
221 Some(self.repr(arena))
222 }
223 }
224}