oxilean_kernel/hash_cons/
key.rs1use crate::Node;
12use crate::{BinderInfo, Expr, FVarId, Level, Literal, Name};
13use std::hash::{Hash, Hasher};
14use std::rc::Rc;
15
16#[derive(Clone, Debug, PartialEq, Eq)]
26pub struct ExprKey(pub Expr);
27
28impl Hash for ExprKey {
29 fn hash<H: Hasher>(&self, state: &mut H) {
30 self.0.hash(state);
33 }
34}
35
36impl ExprKey {
37 #[inline]
39 pub fn new(expr: Expr) -> Self {
40 Self(expr)
41 }
42
43 #[inline]
45 pub fn from_ref(expr: &Expr) -> Self {
46 Self(expr.clone())
47 }
48
49 #[inline]
51 pub fn into_inner(self) -> Expr {
52 self.0
53 }
54
55 #[inline]
57 pub fn inner(&self) -> &Expr {
58 &self.0
59 }
60}
61
62impl ExprKey {
69 pub fn sort(level: Level) -> Self {
71 Self::new(Expr::Sort(level))
72 }
73
74 pub fn bvar(idx: u32) -> Self {
76 Self::new(Expr::BVar(idx))
77 }
78
79 pub fn fvar(id: FVarId) -> Self {
81 Self::new(Expr::FVar(id))
82 }
83
84 pub fn const_(name: Name, levels: Vec<Level>) -> Self {
86 Self::new(Expr::Const(name, levels))
87 }
88
89 pub fn app(f: Expr, a: Expr) -> Self {
91 Self::new(Expr::App(Node::new(f), Node::new(a)))
92 }
93
94 pub fn lam(bi: BinderInfo, name: Name, dom: Expr, body: Expr) -> Self {
96 Self::new(Expr::Lam(bi, name, Node::new(dom), Node::new(body)))
97 }
98
99 pub fn pi(bi: BinderInfo, name: Name, dom: Expr, cod: Expr) -> Self {
101 Self::new(Expr::Pi(bi, name, Node::new(dom), Node::new(cod)))
102 }
103
104 pub fn let_(name: Name, ty: Expr, val: Expr, body: Expr) -> Self {
106 Self::new(Expr::Let(
107 name,
108 Node::new(ty),
109 Node::new(val),
110 Node::new(body),
111 ))
112 }
113
114 pub fn lit(lit: Literal) -> Self {
116 Self::new(Expr::Lit(lit))
117 }
118
119 pub fn proj(name: Name, idx: u32, struct_expr: Expr) -> Self {
121 Self::new(Expr::Proj(name, idx, Node::new(struct_expr)))
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128
129 #[test]
130 fn test_expr_key_eq_same_bvar() {
131 let k1 = ExprKey::bvar(0);
132 let k2 = ExprKey::bvar(0);
133 assert_eq!(k1, k2);
134 }
135
136 #[test]
137 fn test_expr_key_ne_different_bvar() {
138 let k1 = ExprKey::bvar(0);
139 let k2 = ExprKey::bvar(1);
140 assert_ne!(k1, k2);
141 }
142
143 #[test]
144 fn test_expr_key_sort_zero_equals() {
145 let k1 = ExprKey::sort(Level::zero());
146 let k2 = ExprKey::sort(Level::zero());
147 assert_eq!(k1, k2);
148 }
149
150 #[test]
151 fn test_expr_key_fvar_equals() {
152 let id = FVarId::new(42);
153 let k1 = ExprKey::fvar(id);
154 let k2 = ExprKey::fvar(id);
155 assert_eq!(k1, k2);
156 }
157
158 #[test]
159 fn test_expr_key_hash_consistent() {
160 use std::collections::hash_map::DefaultHasher;
161 let k1 = ExprKey::bvar(5);
162 let k2 = ExprKey::bvar(5);
163 let mut h1 = DefaultHasher::new();
164 let mut h2 = DefaultHasher::new();
165 k1.hash(&mut h1);
166 k2.hash(&mut h2);
167 assert_eq!(h1.finish(), h2.finish());
168 }
169
170 #[test]
171 fn test_expr_key_into_inner() {
172 let k = ExprKey::bvar(3);
173 let expr = k.into_inner();
174 assert_eq!(expr, Expr::BVar(3));
175 }
176
177 #[test]
178 fn test_expr_key_from_ref() {
179 let expr = Expr::BVar(7);
180 let k1 = ExprKey::from_ref(&expr);
181 let k2 = ExprKey::bvar(7);
182 assert_eq!(k1, k2);
183 }
184
185 #[test]
186 fn test_expr_key_const_equals() {
187 let name = Name::str("Nat");
188 let k1 = ExprKey::const_(name.clone(), vec![]);
189 let k2 = ExprKey::const_(name, vec![]);
190 assert_eq!(k1, k2);
191 }
192
193 #[test]
194 fn test_expr_key_app_equals() {
195 let f = Expr::BVar(0);
196 let a = Expr::BVar(1);
197 let k1 = ExprKey::app(f.clone(), a.clone());
198 let k2 = ExprKey::app(f, a);
199 assert_eq!(k1, k2);
200 }
201
202 #[test]
203 fn test_expr_key_lam_equals() {
204 let name = Name::str("x");
205 let dom = Expr::Sort(Level::zero());
206 let body = Expr::BVar(0);
207 let k1 = ExprKey::lam(BinderInfo::Default, name.clone(), dom.clone(), body.clone());
208 let k2 = ExprKey::lam(BinderInfo::Default, name, dom, body);
209 assert_eq!(k1, k2);
210 }
211
212 #[test]
213 fn test_expr_key_pi_equals() {
214 let name = Name::str("A");
215 let dom = Expr::Sort(Level::zero());
216 let cod = Expr::BVar(0);
217 let k1 = ExprKey::pi(BinderInfo::Default, name.clone(), dom.clone(), cod.clone());
218 let k2 = ExprKey::pi(BinderInfo::Default, name, dom, cod);
219 assert_eq!(k1, k2);
220 }
221
222 #[test]
223 fn test_expr_key_let_equals() {
224 let name = Name::str("n");
225 let ty = Expr::Sort(Level::zero());
226 let val = Expr::BVar(0);
227 let body = Expr::BVar(1);
228 let k1 = ExprKey::let_(name.clone(), ty.clone(), val.clone(), body.clone());
229 let k2 = ExprKey::let_(name, ty, val, body);
230 assert_eq!(k1, k2);
231 }
232
233 #[test]
234 fn test_expr_key_lit_nat_equals() {
235 let k1 = ExprKey::lit(Literal::nat(42));
236 let k2 = ExprKey::lit(Literal::nat(42));
237 assert_eq!(k1, k2);
238 }
239
240 #[test]
241 fn test_expr_key_proj_equals() {
242 let name = Name::str("fst");
243 let se = Expr::BVar(0);
244 let k1 = ExprKey::proj(name.clone(), 0, se.clone());
245 let k2 = ExprKey::proj(name, 0, se);
246 assert_eq!(k1, k2);
247 }
248
249 #[test]
250 fn test_expr_key_usable_as_hashmap_key() {
251 use std::collections::HashMap;
252 let mut map: HashMap<ExprKey, u32> = HashMap::new();
253 map.insert(ExprKey::bvar(0), 100);
254 map.insert(ExprKey::bvar(1), 200);
255 assert_eq!(map.get(&ExprKey::bvar(0)), Some(&100));
256 assert_eq!(map.get(&ExprKey::bvar(1)), Some(&200));
257 assert_eq!(map.get(&ExprKey::bvar(2)), None);
258 }
259}