oxilean_kernel/env_index/
functions.rs1use std::collections::HashMap;
7
8use super::types::{EnvIndex, IndexStats, LookupResult, ModuleIndex, NameIndex, TypeIndex};
9
10impl NameIndex {
15 pub fn new() -> Self {
17 NameIndex {
18 name_to_id: HashMap::new(),
19 id_to_name: Vec::new(),
20 }
21 }
22
23 pub fn insert(&mut self, name: &str) -> u32 {
28 if let Some(&id) = self.name_to_id.get(name) {
29 return id;
30 }
31 let id = self.id_to_name.len() as u32;
32 self.id_to_name.push(name.to_owned());
33 self.name_to_id.insert(name.to_owned(), id);
34 id
35 }
36
37 pub fn lookup_id(&self, name: &str) -> Option<u32> {
39 self.name_to_id.get(name).copied()
40 }
41
42 pub fn lookup_name(&self, id: u32) -> Option<&str> {
44 self.id_to_name.get(id as usize).map(String::as_str)
45 }
46
47 pub fn len(&self) -> usize {
49 self.id_to_name.len()
50 }
51
52 pub fn is_empty(&self) -> bool {
54 self.id_to_name.is_empty()
55 }
56}
57
58impl Default for NameIndex {
59 fn default() -> Self {
60 NameIndex::new()
61 }
62}
63
64impl ModuleIndex {
69 pub fn new() -> Self {
71 ModuleIndex {
72 modules: HashMap::new(),
73 }
74 }
75
76 pub fn add(&mut self, name: &str, id: u32) {
80 let ns = namespace_of(name).to_owned();
81 self.modules.entry(ns).or_default().push(id);
82 }
83
84 pub fn lookup_namespace(&self, prefix: &str) -> Vec<u32> {
88 self.modules.get(prefix).cloned().unwrap_or_default()
89 }
90
91 pub fn all_namespaces(&self) -> Vec<String> {
93 let mut ns: Vec<String> = self.modules.keys().cloned().collect();
94 ns.sort();
95 ns
96 }
97}
98
99impl Default for ModuleIndex {
100 fn default() -> Self {
101 ModuleIndex::new()
102 }
103}
104
105impl TypeIndex {
110 pub fn new() -> Self {
112 TypeIndex {
113 by_sort: HashMap::new(),
114 by_arity: HashMap::new(),
115 }
116 }
117
118 pub fn add_by_sort(&mut self, sort_level: u8, id: u32) {
120 self.by_sort.entry(sort_level).or_default().push(id);
121 }
122
123 pub fn add_by_arity(&mut self, arity: u32, id: u32) {
125 self.by_arity.entry(arity).or_default().push(id);
126 }
127
128 pub fn lookup_by_sort(&self, sort_level: u8) -> Vec<u32> {
130 self.by_sort.get(&sort_level).cloned().unwrap_or_default()
131 }
132
133 pub fn lookup_by_arity(&self, arity: u32) -> Vec<u32> {
135 self.by_arity.get(&arity).cloned().unwrap_or_default()
136 }
137}
138
139impl Default for TypeIndex {
140 fn default() -> Self {
141 TypeIndex::new()
142 }
143}
144
145impl EnvIndex {
150 pub fn new() -> Self {
152 EnvIndex {
153 name_idx: NameIndex::new(),
154 type_idx: TypeIndex::new(),
155 module_idx: ModuleIndex::new(),
156 size: 0,
157 }
158 }
159
160 pub fn insert(&mut self, name: &str) -> u32 {
169 let already = self.name_idx.lookup_id(name).is_some();
170 let id = self.name_idx.insert(name);
171 if !already {
172 self.module_idx.add(name, id);
173 self.size += 1;
174 }
175 id
176 }
177
178 pub fn lookup<'a>(&'a self, name: &str) -> Option<LookupResult<'a>> {
180 let id = self.name_idx.lookup_id(name)?;
181 let stored_name = self.name_idx.lookup_name(id)?;
182 Some(LookupResult {
183 id,
184 name: stored_name,
185 })
186 }
187
188 pub fn by_namespace(&self, prefix: &str) -> Vec<u32> {
190 self.module_idx.lookup_namespace(prefix)
191 }
192
193 pub fn stats(&self) -> IndexStats {
198 IndexStats {
199 total: self.size,
200 by_kind: HashMap::new(),
201 namespaces: self.module_idx.modules.len(),
202 }
203 }
204}
205
206impl Default for EnvIndex {
207 fn default() -> Self {
208 EnvIndex::new()
209 }
210}
211
212pub fn namespace_of(name: &str) -> &str {
222 match name.rfind('.') {
223 Some(pos) => &name[..pos],
224 None => "",
225 }
226}
227
228pub fn is_in_namespace(name: &str, ns: &str) -> bool {
241 namespace_of(name) == ns
242}
243
244#[cfg(test)]
249mod tests {
250 use super::*;
251
252 #[test]
255 fn test_namespace_of_dotted() {
256 assert_eq!(namespace_of("Nat.add"), "Nat");
257 }
258
259 #[test]
260 fn test_namespace_of_nested() {
261 assert_eq!(namespace_of("List.Lex.lt"), "List.Lex");
262 }
263
264 #[test]
265 fn test_namespace_of_top_level() {
266 assert_eq!(namespace_of("succ"), "");
267 }
268
269 #[test]
270 fn test_namespace_of_empty() {
271 assert_eq!(namespace_of(""), "");
272 }
273
274 #[test]
277 fn test_is_in_namespace_true() {
278 assert!(is_in_namespace("Nat.add", "Nat"));
279 }
280
281 #[test]
282 fn test_is_in_namespace_false() {
283 assert!(!is_in_namespace("Nat.add", "List"));
284 }
285
286 #[test]
287 fn test_is_in_namespace_top_level() {
288 assert!(is_in_namespace("succ", ""));
289 }
290
291 #[test]
292 fn test_is_in_namespace_prefix_not_subset() {
293 assert!(!is_in_namespace("Nat.add", "Na"));
295 }
296
297 #[test]
300 fn test_name_index_new_empty() {
301 let idx = NameIndex::new();
302 assert!(idx.is_empty());
303 assert_eq!(idx.len(), 0);
304 }
305
306 #[test]
307 fn test_name_index_insert_and_lookup_id() {
308 let mut idx = NameIndex::new();
309 let id = idx.insert("Nat.add");
310 assert_eq!(idx.lookup_id("Nat.add"), Some(id));
311 }
312
313 #[test]
314 fn test_name_index_insert_idempotent() {
315 let mut idx = NameIndex::new();
316 let id1 = idx.insert("Nat.add");
317 let id2 = idx.insert("Nat.add");
318 assert_eq!(id1, id2);
319 assert_eq!(idx.len(), 1);
320 }
321
322 #[test]
323 fn test_name_index_lookup_name() {
324 let mut idx = NameIndex::new();
325 let id = idx.insert("List.map");
326 assert_eq!(idx.lookup_name(id), Some("List.map"));
327 }
328
329 #[test]
330 fn test_name_index_lookup_id_missing() {
331 let idx = NameIndex::new();
332 assert_eq!(idx.lookup_id("unknown"), None);
333 }
334
335 #[test]
336 fn test_name_index_lookup_name_out_of_range() {
337 let idx = NameIndex::new();
338 assert_eq!(idx.lookup_name(99), None);
339 }
340
341 #[test]
342 fn test_name_index_multiple_entries() {
343 let mut idx = NameIndex::new();
344 let ids: Vec<u32> = ["a", "b", "c"].iter().map(|n| idx.insert(n)).collect();
345 assert_eq!(ids, vec![0, 1, 2]);
346 assert_eq!(idx.len(), 3);
347 }
348
349 #[test]
352 fn test_module_index_new_empty() {
353 let idx = ModuleIndex::new();
354 assert!(idx.all_namespaces().is_empty());
355 }
356
357 #[test]
358 fn test_module_index_add_and_lookup() {
359 let mut idx = ModuleIndex::new();
360 idx.add("Nat.add", 0);
361 idx.add("Nat.sub", 1);
362 let mut ids = idx.lookup_namespace("Nat");
363 ids.sort();
364 assert_eq!(ids, vec![0, 1]);
365 }
366
367 #[test]
368 fn test_module_index_lookup_missing() {
369 let idx = ModuleIndex::new();
370 assert!(idx.lookup_namespace("List").is_empty());
371 }
372
373 #[test]
374 fn test_module_index_all_namespaces_sorted() {
375 let mut idx = ModuleIndex::new();
376 idx.add("Nat.add", 0);
377 idx.add("List.map", 1);
378 idx.add("succ", 2);
379 let ns = idx.all_namespaces();
380 let mut expected = vec!["", "List", "Nat"];
381 expected.sort();
382 assert_eq!(ns, expected);
383 }
384
385 #[test]
388 fn test_type_index_by_sort() {
389 let mut idx = TypeIndex::new();
390 idx.add_by_sort(0, 10);
391 idx.add_by_sort(0, 20);
392 idx.add_by_sort(1, 30);
393 let mut s0 = idx.lookup_by_sort(0);
394 s0.sort();
395 assert_eq!(s0, vec![10, 20]);
396 assert_eq!(idx.lookup_by_sort(1), vec![30]);
397 }
398
399 #[test]
400 fn test_type_index_by_arity() {
401 let mut idx = TypeIndex::new();
402 idx.add_by_arity(2, 5);
403 idx.add_by_arity(2, 6);
404 idx.add_by_arity(0, 7);
405 let mut a2 = idx.lookup_by_arity(2);
406 a2.sort();
407 assert_eq!(a2, vec![5, 6]);
408 }
409
410 #[test]
411 fn test_type_index_missing_sort() {
412 let idx = TypeIndex::new();
413 assert!(idx.lookup_by_sort(5).is_empty());
414 }
415
416 #[test]
417 fn test_type_index_missing_arity() {
418 let idx = TypeIndex::new();
419 assert!(idx.lookup_by_arity(3).is_empty());
420 }
421
422 #[test]
425 fn test_env_index_new_empty() {
426 let idx = EnvIndex::new();
427 assert_eq!(idx.size, 0);
428 }
429
430 #[test]
431 fn test_env_index_insert_and_lookup() {
432 let mut idx = EnvIndex::new();
433 let id = idx.insert("Nat.add");
434 let result = idx.lookup("Nat.add").expect("should find inserted name");
435 assert_eq!(result.id, id);
436 assert_eq!(result.name, "Nat.add");
437 }
438
439 #[test]
440 fn test_env_index_insert_idempotent() {
441 let mut idx = EnvIndex::new();
442 idx.insert("Nat.add");
443 idx.insert("Nat.add");
444 assert_eq!(idx.size, 1);
445 }
446
447 #[test]
448 fn test_env_index_lookup_missing() {
449 let idx = EnvIndex::new();
450 assert!(idx.lookup("ghost").is_none());
451 }
452
453 #[test]
454 fn test_env_index_by_namespace() {
455 let mut idx = EnvIndex::new();
456 idx.insert("Nat.add");
457 idx.insert("Nat.sub");
458 idx.insert("List.map");
459 let mut nat = idx.by_namespace("Nat");
460 nat.sort();
461 assert_eq!(nat.len(), 2);
462 assert!(idx.by_namespace("List").len() == 1);
463 }
464
465 #[test]
466 fn test_env_index_stats() {
467 let mut idx = EnvIndex::new();
468 idx.insert("Nat.add");
469 idx.insert("List.map");
470 idx.insert("succ");
471 let s = idx.stats();
472 assert_eq!(s.total, 3);
473 assert_eq!(s.namespaces, 3); }
475
476 #[test]
477 fn test_env_index_stats_display() {
478 let idx = EnvIndex::new();
479 let s = idx.stats();
480 let text = format!("{}", s);
481 assert!(text.contains("IndexStats"));
482 }
483
484 #[test]
485 fn test_env_index_type_idx_sort() {
486 let mut idx = EnvIndex::new();
487 let id = idx.insert("Prop");
488 idx.type_idx.add_by_sort(0, id);
489 let results = idx.type_idx.lookup_by_sort(0);
490 assert_eq!(results, vec![id]);
491 }
492
493 #[test]
494 fn test_env_index_type_idx_arity() {
495 let mut idx = EnvIndex::new();
496 let id = idx.insert("Nat.add");
497 idx.type_idx.add_by_arity(2, id);
498 let results = idx.type_idx.lookup_by_arity(2);
499 assert_eq!(results, vec![id]);
500 }
501}