Skip to main content

aver/nan_value/
compare.rs

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        // Inline variant fast path (no arena indirection)
22        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                    // Same constructor — compare field(s)
28                    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                        // Cross-representation: extract the single field from each side
33                        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}