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