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        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}