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