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