Skip to main content

aver_memory/
compare.rs

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