Skip to main content

oxilean_kernel/name/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use std::collections::{HashMap, HashSet, VecDeque};
6
7/// A clock that measures elapsed time in a loop.
8#[allow(dead_code)]
9pub struct LoopClock {
10    start: std::time::Instant,
11    iters: u64,
12}
13#[allow(dead_code)]
14impl LoopClock {
15    /// Starts the clock.
16    pub fn start() -> Self {
17        Self {
18            start: std::time::Instant::now(),
19            iters: 0,
20        }
21    }
22    /// Records one iteration.
23    pub fn tick(&mut self) {
24        self.iters += 1;
25    }
26    /// Returns the elapsed time in microseconds.
27    pub fn elapsed_us(&self) -> f64 {
28        self.start.elapsed().as_secs_f64() * 1e6
29    }
30    /// Returns the average microseconds per iteration.
31    pub fn avg_us_per_iter(&self) -> f64 {
32        if self.iters == 0 {
33            return 0.0;
34        }
35        self.elapsed_us() / self.iters as f64
36    }
37    /// Returns the number of iterations.
38    pub fn iters(&self) -> u64 {
39        self.iters
40    }
41}
42/// A monotonic timestamp in microseconds.
43#[allow(dead_code)]
44#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
45pub struct Timestamp(u64);
46#[allow(dead_code)]
47impl Timestamp {
48    /// Creates a timestamp from microseconds.
49    pub const fn from_us(us: u64) -> Self {
50        Self(us)
51    }
52    /// Returns the timestamp in microseconds.
53    pub fn as_us(self) -> u64 {
54        self.0
55    }
56    /// Returns the duration between two timestamps.
57    pub fn elapsed_since(self, earlier: Timestamp) -> u64 {
58        self.0.saturating_sub(earlier.0)
59    }
60}
61/// A fresh-name generator.
62///
63/// Generates unique names by appending an incrementing counter suffix.
64#[derive(Debug, Clone)]
65pub struct NameGenerator {
66    base: Name,
67    counter: u64,
68}
69impl NameGenerator {
70    /// Create a generator with the given base name.
71    pub fn new(base: Name) -> Self {
72        Self { base, counter: 0 }
73    }
74    /// Create a generator with a string base.
75    pub fn with_base(s: impl Into<String>) -> Self {
76        Self::new(Name::str(s))
77    }
78    /// Generate the next fresh name.
79    #[allow(clippy::should_implement_trait)]
80    pub fn next(&mut self) -> Name {
81        let n = self.base.clone().append_num(self.counter);
82        self.counter += 1;
83        n
84    }
85    /// Peek at the next name without advancing.
86    pub fn peek(&self) -> Name {
87        self.base.clone().append_num(self.counter)
88    }
89    /// Reset the counter to 0.
90    pub fn reset(&mut self) {
91        self.counter = 0;
92    }
93    /// Current counter value.
94    pub fn count(&self) -> u64 {
95        self.counter
96    }
97}
98/// A type-safe wrapper around a `u32` identifier.
99#[allow(dead_code)]
100#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
101pub struct TypedId<T> {
102    pub(super) id: u32,
103    _phantom: std::marker::PhantomData<T>,
104}
105#[allow(dead_code)]
106impl<T> TypedId<T> {
107    /// Creates a new typed ID.
108    pub const fn new(id: u32) -> Self {
109        Self {
110            id,
111            _phantom: std::marker::PhantomData,
112        }
113    }
114    /// Returns the raw `u32` ID.
115    pub fn raw(&self) -> u32 {
116        self.id
117    }
118}
119/// Interns strings to save memory (each unique string stored once).
120#[allow(dead_code)]
121pub struct StringInterner {
122    strings: Vec<String>,
123    map: std::collections::HashMap<String, u32>,
124}
125#[allow(dead_code)]
126impl StringInterner {
127    /// Creates a new string interner.
128    pub fn new() -> Self {
129        Self {
130            strings: Vec::new(),
131            map: std::collections::HashMap::new(),
132        }
133    }
134    /// Interns `s` and returns its ID.
135    pub fn intern(&mut self, s: &str) -> u32 {
136        if let Some(&id) = self.map.get(s) {
137            return id;
138        }
139        let id = self.strings.len() as u32;
140        self.strings.push(s.to_string());
141        self.map.insert(s.to_string(), id);
142        id
143    }
144    /// Returns the string for `id`.
145    pub fn get(&self, id: u32) -> Option<&str> {
146        self.strings.get(id as usize).map(|s| s.as_str())
147    }
148    /// Returns the total number of interned strings.
149    pub fn len(&self) -> usize {
150        self.strings.len()
151    }
152    /// Returns `true` if empty.
153    pub fn is_empty(&self) -> bool {
154        self.strings.is_empty()
155    }
156}
157/// A trie (prefix tree) for efficient name lookups.
158///
159/// Each node in the trie corresponds to one component of a hierarchical name.
160/// Useful for namespace browsing and completion in the LSP server.
161#[derive(Debug, Clone)]
162pub struct NameTrie<V> {
163    /// Value stored at this node (if any).
164    pub(super) value: Option<V>,
165    /// Children indexed by string component.
166    pub(super) string_children: Vec<(String, NameTrie<V>)>,
167    /// Children indexed by numeric component.
168    pub(super) num_children: Vec<(u64, NameTrie<V>)>,
169}
170impl<V: Clone> NameTrie<V> {
171    /// Create an empty trie.
172    pub fn new() -> Self {
173        Self::default()
174    }
175    /// Insert a name-value pair into the trie.
176    pub fn insert(&mut self, name: &Name, value: V) {
177        match name {
178            Name::Anonymous => {
179                self.value = Some(value);
180            }
181            Name::Str(parent, s) => {
182                let child = if let Some(idx) = self.string_children.iter().position(|(k, _)| k == s)
183                {
184                    &mut self.string_children[idx].1
185                } else {
186                    self.string_children.push((s.clone(), NameTrie::new()));
187                    let last = self.string_children.len() - 1;
188                    &mut self.string_children[last].1
189                };
190                child.insert(parent, value);
191            }
192            Name::Num(parent, n) => {
193                let child = if let Some(idx) = self.num_children.iter().position(|(k, _)| k == n) {
194                    &mut self.num_children[idx].1
195                } else {
196                    self.num_children.push((*n, NameTrie::new()));
197                    let last = self.num_children.len() - 1;
198                    &mut self.num_children[last].1
199                };
200                child.insert(parent, value);
201            }
202        }
203    }
204    /// Look up a name in the trie.
205    pub fn lookup(&self, name: &Name) -> Option<&V> {
206        match name {
207            Name::Anonymous => self.value.as_ref(),
208            Name::Str(parent, s) => {
209                let child = self
210                    .string_children
211                    .iter()
212                    .find(|(k, _)| k == s)
213                    .map(|(_, v)| v)?;
214                child.lookup(parent)
215            }
216            Name::Num(parent, n) => {
217                let child = self
218                    .num_children
219                    .iter()
220                    .find(|(k, _)| k == n)
221                    .map(|(_, v)| v)?;
222                child.lookup(parent)
223            }
224        }
225    }
226    /// Check whether the trie contains the given name.
227    pub fn contains(&self, name: &Name) -> bool {
228        self.lookup(name).is_some()
229    }
230    /// Count all values stored in the trie.
231    pub fn count(&self) -> usize {
232        let self_count = if self.value.is_some() { 1 } else { 0 };
233        let str_count: usize = self.string_children.iter().map(|(_, c)| c.count()).sum();
234        let num_count: usize = self.num_children.iter().map(|(_, c)| c.count()).sum();
235        self_count + str_count + num_count
236    }
237    /// Collect all (name, value) pairs in the trie.
238    pub fn to_vec(&self) -> Vec<(Name, V)> {
239        let mut result = Vec::new();
240        self.collect_all(Name::Anonymous, &mut result);
241        result
242    }
243    fn collect_all(&self, prefix: Name, result: &mut Vec<(Name, V)>) {
244        if let Some(v) = &self.value {
245            result.push((prefix.clone(), v.clone()));
246        }
247        for (s, child) in &self.string_children {
248            let name = prefix.clone().append_str(s.as_str());
249            child.collect_all(name, result);
250        }
251        for (n, child) in &self.num_children {
252            let name = prefix.clone().append_num(*n);
253            child.collect_all(name, result);
254        }
255    }
256}
257/// A FIFO work queue.
258#[allow(dead_code)]
259pub struct WorkQueue<T> {
260    items: std::collections::VecDeque<T>,
261}
262#[allow(dead_code)]
263impl<T> WorkQueue<T> {
264    /// Creates a new empty queue.
265    pub fn new() -> Self {
266        Self {
267            items: std::collections::VecDeque::new(),
268        }
269    }
270    /// Enqueues a work item.
271    pub fn enqueue(&mut self, item: T) {
272        self.items.push_back(item);
273    }
274    /// Dequeues the next work item.
275    pub fn dequeue(&mut self) -> Option<T> {
276        self.items.pop_front()
277    }
278    /// Returns `true` if empty.
279    pub fn is_empty(&self) -> bool {
280        self.items.is_empty()
281    }
282    /// Returns the number of pending items.
283    pub fn len(&self) -> usize {
284        self.items.len()
285    }
286}
287/// A sequence number that can be compared for ordering.
288#[allow(dead_code)]
289#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
290pub struct SeqNum(u64);
291#[allow(dead_code)]
292impl SeqNum {
293    /// Creates sequence number zero.
294    pub const ZERO: SeqNum = SeqNum(0);
295    /// Advances the sequence number by one.
296    pub fn next(self) -> SeqNum {
297        SeqNum(self.0 + 1)
298    }
299    /// Returns the raw value.
300    pub fn value(self) -> u64 {
301        self.0
302    }
303}
304/// A set of non-overlapping integer intervals.
305#[allow(dead_code)]
306pub struct IntervalSet {
307    intervals: Vec<(i64, i64)>,
308}
309#[allow(dead_code)]
310impl IntervalSet {
311    /// Creates an empty interval set.
312    pub fn new() -> Self {
313        Self {
314            intervals: Vec::new(),
315        }
316    }
317    /// Adds the interval `[lo, hi]` to the set.
318    pub fn add(&mut self, lo: i64, hi: i64) {
319        if lo > hi {
320            return;
321        }
322        let mut new_lo = lo;
323        let mut new_hi = hi;
324        let mut i = 0;
325        while i < self.intervals.len() {
326            let (il, ih) = self.intervals[i];
327            if ih < new_lo - 1 {
328                i += 1;
329                continue;
330            }
331            if il > new_hi + 1 {
332                break;
333            }
334            new_lo = new_lo.min(il);
335            new_hi = new_hi.max(ih);
336            self.intervals.remove(i);
337        }
338        self.intervals.insert(i, (new_lo, new_hi));
339    }
340    /// Returns `true` if `x` is in the set.
341    pub fn contains(&self, x: i64) -> bool {
342        self.intervals.iter().any(|&(lo, hi)| x >= lo && x <= hi)
343    }
344    /// Returns the number of intervals.
345    pub fn num_intervals(&self) -> usize {
346        self.intervals.len()
347    }
348    /// Returns the total count of integers covered.
349    pub fn cardinality(&self) -> i64 {
350        self.intervals.iter().map(|&(lo, hi)| hi - lo + 1).sum()
351    }
352}
353/// A mapping from `Name` to `V`.
354///
355/// Wraps `HashMap<Name, V>` for convenient use in the elaborator and kernel.
356#[derive(Debug, Clone, Default)]
357pub struct NameMap<V> {
358    pub(super) inner: HashMap<Name, V>,
359}
360impl<V> NameMap<V> {
361    /// Create an empty `NameMap`.
362    pub fn new() -> Self {
363        Self {
364            inner: HashMap::new(),
365        }
366    }
367    /// Create a `NameMap` with the given capacity.
368    pub fn with_capacity(cap: usize) -> Self {
369        Self {
370            inner: HashMap::with_capacity(cap),
371        }
372    }
373    /// Insert or overwrite a mapping.
374    pub fn insert(&mut self, name: Name, value: V) -> Option<V> {
375        self.inner.insert(name, value)
376    }
377    /// Get a reference to the value for `name`.
378    pub fn get(&self, name: &Name) -> Option<&V> {
379        self.inner.get(name)
380    }
381    /// Get a mutable reference to the value for `name`.
382    pub fn get_mut(&mut self, name: &Name) -> Option<&mut V> {
383        self.inner.get_mut(name)
384    }
385    /// Remove and return the value for `name`.
386    pub fn remove(&mut self, name: &Name) -> Option<V> {
387        self.inner.remove(name)
388    }
389    /// Check whether `name` has a mapping.
390    pub fn contains_key(&self, name: &Name) -> bool {
391        self.inner.contains_key(name)
392    }
393    /// Number of mappings.
394    pub fn len(&self) -> usize {
395        self.inner.len()
396    }
397    /// Returns `true` if empty.
398    pub fn is_empty(&self) -> bool {
399        self.inner.is_empty()
400    }
401    /// Iterate over key-value pairs.
402    pub fn iter(&self) -> impl Iterator<Item = (&Name, &V)> {
403        self.inner.iter()
404    }
405    /// Iterate over keys.
406    pub fn keys(&self) -> impl Iterator<Item = &Name> {
407        self.inner.keys()
408    }
409    /// Iterate over values.
410    pub fn values(&self) -> impl Iterator<Item = &V> {
411        self.inner.values()
412    }
413    /// Filter entries by a predicate on the name.
414    pub fn filter_by_namespace(&self, ns: &Name) -> Vec<(&Name, &V)> {
415        self.inner
416            .iter()
417            .filter(|(n, _)| n.has_prefix(ns))
418            .collect()
419    }
420    /// Collect all names in sorted order.
421    pub fn sorted_names(&self) -> Vec<Name> {
422        let mut names: Vec<Name> = self.inner.keys().cloned().collect();
423        names.sort();
424        names
425    }
426    /// Get or insert a default value.
427    pub fn entry_or_insert(&mut self, name: Name, value: V) -> &mut V {
428        self.inner.entry(name).or_insert(value)
429    }
430}
431/// A pair of values useful for before/after comparisons.
432#[allow(dead_code)]
433#[allow(missing_docs)]
434pub struct BeforeAfter<T> {
435    /// Value before the transformation.
436    pub before: T,
437    /// Value after the transformation.
438    pub after: T,
439}
440#[allow(dead_code)]
441impl<T: PartialEq> BeforeAfter<T> {
442    /// Creates a new before/after pair.
443    pub fn new(before: T, after: T) -> Self {
444        Self { before, after }
445    }
446    /// Returns `true` if before equals after (no change).
447    pub fn unchanged(&self) -> bool {
448        self.before == self.after
449    }
450}
451/// A simple LIFO work queue.
452#[allow(dead_code)]
453pub struct WorkStack<T> {
454    items: Vec<T>,
455}
456#[allow(dead_code)]
457impl<T> WorkStack<T> {
458    /// Creates a new empty stack.
459    pub fn new() -> Self {
460        Self { items: Vec::new() }
461    }
462    /// Pushes a work item.
463    pub fn push(&mut self, item: T) {
464        self.items.push(item);
465    }
466    /// Pops the next work item.
467    pub fn pop(&mut self) -> Option<T> {
468        self.items.pop()
469    }
470    /// Returns `true` if empty.
471    pub fn is_empty(&self) -> bool {
472        self.items.is_empty()
473    }
474    /// Returns the number of pending work items.
475    pub fn len(&self) -> usize {
476        self.items.len()
477    }
478}
479/// A generation counter for validity tracking.
480#[allow(dead_code)]
481#[derive(Clone, Copy, Debug, PartialEq, Eq)]
482pub struct Generation(u32);
483#[allow(dead_code)]
484impl Generation {
485    /// The initial generation.
486    pub const INITIAL: Generation = Generation(0);
487    /// Advances to the next generation.
488    pub fn advance(self) -> Generation {
489        Generation(self.0 + 1)
490    }
491    /// Returns the raw generation number.
492    pub fn number(self) -> u32 {
493        self.0
494    }
495}
496/// A name with an optional namespace alias.
497///
498/// Used for name resolution when the user writes `open Nat` and then `add`.
499#[derive(Debug, Clone, PartialEq, Eq)]
500pub struct QualifiedName {
501    /// The full canonical name.
502    pub canonical: Name,
503    /// An optional shorter alias (e.g. after `open`).
504    pub alias: Option<Name>,
505}
506impl QualifiedName {
507    /// Create a new `QualifiedName` with no alias.
508    pub fn new(canonical: Name) -> Self {
509        Self {
510            canonical,
511            alias: None,
512        }
513    }
514    /// Create a `QualifiedName` with an alias.
515    pub fn with_alias(canonical: Name, alias: Name) -> Self {
516        Self {
517            canonical,
518            alias: Some(alias),
519        }
520    }
521    /// The preferred display name (alias if present, otherwise canonical).
522    pub fn preferred(&self) -> &Name {
523        self.alias.as_ref().unwrap_or(&self.canonical)
524    }
525}
526/// An interning pool for `Name` strings.
527#[allow(dead_code)]
528pub struct NamePool {
529    names: Vec<String>,
530    index: std::collections::HashMap<String, usize>,
531}
532#[allow(dead_code)]
533impl NamePool {
534    /// Creates an empty name pool.
535    pub fn new() -> Self {
536        Self {
537            names: Vec::new(),
538            index: std::collections::HashMap::new(),
539        }
540    }
541    /// Interns `name` and returns its ID.
542    pub fn intern(&mut self, name: &str) -> usize {
543        if let Some(&id) = self.index.get(name) {
544            return id;
545        }
546        let id = self.names.len();
547        self.names.push(name.to_string());
548        self.index.insert(name.to_string(), id);
549        id
550    }
551    /// Returns the name for `id`, or `None`.
552    pub fn get(&self, id: usize) -> Option<&str> {
553        self.names.get(id).map(|s| s.as_str())
554    }
555    /// Returns the number of interned names.
556    pub fn len(&self) -> usize {
557        self.names.len()
558    }
559    /// Returns `true` if the pool is empty.
560    pub fn is_empty(&self) -> bool {
561        self.names.is_empty()
562    }
563}
564/// Resolves unqualified names to fully-qualified names given a namespace.
565#[allow(dead_code)]
566pub struct NameResolver {
567    namespace: Vec<String>,
568    registered: std::collections::HashSet<String>,
569}
570#[allow(dead_code)]
571impl NameResolver {
572    /// Creates a new resolver in the root namespace.
573    pub fn new() -> Self {
574        Self {
575            namespace: Vec::new(),
576            registered: std::collections::HashSet::new(),
577        }
578    }
579    /// Registers a fully-qualified name.
580    pub fn register(&mut self, fqn: impl Into<String>) {
581        self.registered.insert(fqn.into());
582    }
583    /// Enters a sub-namespace.
584    pub fn enter(&mut self, ns: impl Into<String>) {
585        self.namespace.push(ns.into());
586    }
587    /// Exits the current sub-namespace.
588    pub fn exit(&mut self) {
589        self.namespace.pop();
590    }
591    /// Returns the current namespace as a dot-separated string.
592    pub fn current_ns(&self) -> String {
593        self.namespace.join(".")
594    }
595    /// Resolves `name` to a fully-qualified name.
596    pub fn resolve(&self, name: &str) -> String {
597        if self.namespace.is_empty() {
598            return name.to_string();
599        }
600        let fqn = format!("{}.{}", self.namespace.join("."), name);
601        if self.registered.contains(&fqn) {
602            fqn
603        } else {
604            name.to_string()
605        }
606    }
607}
608/// A growable ring buffer with fixed maximum capacity.
609#[allow(dead_code)]
610pub struct RingBuffer<T> {
611    data: Vec<Option<T>>,
612    head: usize,
613    tail: usize,
614    count: usize,
615    capacity: usize,
616}
617#[allow(dead_code)]
618impl<T> RingBuffer<T> {
619    /// Creates a new ring buffer with the given capacity.
620    pub fn new(capacity: usize) -> Self {
621        let mut data = Vec::with_capacity(capacity);
622        for _ in 0..capacity {
623            data.push(None);
624        }
625        Self {
626            data,
627            head: 0,
628            tail: 0,
629            count: 0,
630            capacity,
631        }
632    }
633    /// Pushes a value, overwriting the oldest if full.
634    pub fn push(&mut self, val: T) {
635        if self.count == self.capacity {
636            self.data[self.head] = Some(val);
637            self.head = (self.head + 1) % self.capacity;
638            self.tail = (self.tail + 1) % self.capacity;
639        } else {
640            self.data[self.tail] = Some(val);
641            self.tail = (self.tail + 1) % self.capacity;
642            self.count += 1;
643        }
644    }
645    /// Pops the oldest value.
646    pub fn pop(&mut self) -> Option<T> {
647        if self.count == 0 {
648            return None;
649        }
650        let val = self.data[self.head].take();
651        self.head = (self.head + 1) % self.capacity;
652        self.count -= 1;
653        val
654    }
655    /// Returns the number of elements.
656    pub fn len(&self) -> usize {
657        self.count
658    }
659    /// Returns `true` if empty.
660    pub fn is_empty(&self) -> bool {
661        self.count == 0
662    }
663    /// Returns `true` if at capacity.
664    pub fn is_full(&self) -> bool {
665        self.count == self.capacity
666    }
667}
668/// A bidirectional map between two types.
669#[allow(dead_code)]
670pub struct BiMap<A: std::hash::Hash + Eq + Clone, B: std::hash::Hash + Eq + Clone> {
671    forward: std::collections::HashMap<A, B>,
672    backward: std::collections::HashMap<B, A>,
673}
674#[allow(dead_code)]
675impl<A: std::hash::Hash + Eq + Clone, B: std::hash::Hash + Eq + Clone> BiMap<A, B> {
676    /// Creates an empty bidirectional map.
677    pub fn new() -> Self {
678        Self {
679            forward: std::collections::HashMap::new(),
680            backward: std::collections::HashMap::new(),
681        }
682    }
683    /// Inserts a pair `(a, b)`.
684    pub fn insert(&mut self, a: A, b: B) {
685        self.forward.insert(a.clone(), b.clone());
686        self.backward.insert(b, a);
687    }
688    /// Looks up `b` for a given `a`.
689    pub fn get_b(&self, a: &A) -> Option<&B> {
690        self.forward.get(a)
691    }
692    /// Looks up `a` for a given `b`.
693    pub fn get_a(&self, b: &B) -> Option<&A> {
694        self.backward.get(b)
695    }
696    /// Returns the number of pairs.
697    pub fn len(&self) -> usize {
698        self.forward.len()
699    }
700    /// Returns `true` if empty.
701    pub fn is_empty(&self) -> bool {
702        self.forward.is_empty()
703    }
704}
705/// A hierarchical name.
706///
707/// Names are used to identify constants, inductives, and other declarations.
708/// They form a tree structure: `Nat.add.comm` is represented as
709/// `Str(Str(Str(Anonymous, "Nat"), "add"), "comm")`.
710#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
711pub enum Name {
712    /// The anonymous (root) name.
713    #[default]
714    Anonymous,
715    /// A string component: parent name + string.
716    Str(Box<Name>, String),
717    /// A numeric component: parent name + number.
718    Num(Box<Name>, u64),
719}
720impl Name {
721    /// Create a simple string name (no parent).
722    pub fn str(s: impl Into<String>) -> Self {
723        Name::Str(Box::new(Name::Anonymous), s.into())
724    }
725    /// Append a string component to this name.
726    pub fn append_str(self, s: impl Into<String>) -> Self {
727        Name::Str(Box::new(self), s.into())
728    }
729    /// Append a numeric component to this name.
730    pub fn append_num(self, n: u64) -> Self {
731        Name::Num(Box::new(self), n)
732    }
733    /// Check if this is the anonymous name.
734    pub fn is_anonymous(&self) -> bool {
735        matches!(self, Name::Anonymous)
736    }
737    /// Create a `Name` from a dot-separated string.
738    ///
739    /// `Name::from_str("Nat.add.comm")` produces the same as
740    /// `Name::str("Nat").append_str("add").append_str("comm")`.
741    #[allow(clippy::should_implement_trait)]
742    pub fn from_str(s: &str) -> Self {
743        let mut parts = s.split('.');
744        let first = match parts.next() {
745            None | Some("") => return Name::Anonymous,
746            Some(f) => f,
747        };
748        let mut name = Name::str(first);
749        for part in parts {
750            if part.is_empty() {
751                continue;
752            }
753            if let Ok(n) = part.parse::<u64>() {
754                name = name.append_num(n);
755            } else {
756                name = name.append_str(part);
757            }
758        }
759        name
760    }
761    /// Returns the depth (number of components) of this name.
762    ///
763    /// `Anonymous` has depth 0, `Name::str("Nat")` has depth 1,
764    /// `Name::str("Nat").append_str("add")` has depth 2.
765    pub fn depth(&self) -> usize {
766        match self {
767            Name::Anonymous => 0,
768            Name::Str(parent, _) | Name::Num(parent, _) => 1 + parent.depth(),
769        }
770    }
771    /// Return the last string component of this name, if any.
772    ///
773    /// For `Nat.add`, returns `Some("add")`.
774    pub fn last_str(&self) -> Option<&str> {
775        match self {
776            Name::Anonymous => None,
777            Name::Str(_, s) => Some(s.as_str()),
778            Name::Num(parent, _) => parent.last_str(),
779        }
780    }
781    /// Return the last numeric component, if any.
782    pub fn last_num(&self) -> Option<u64> {
783        match self {
784            Name::Num(_, n) => Some(*n),
785            Name::Str(parent, _) => parent.last_num(),
786            Name::Anonymous => None,
787        }
788    }
789    /// Return the root (top-level) component as a string.
790    ///
791    /// For `Nat.add.comm`, returns `"Nat"`.
792    pub fn root(&self) -> Option<&str> {
793        match self {
794            Name::Anonymous => None,
795            Name::Str(parent, s) => {
796                if parent.is_anonymous() {
797                    Some(s.as_str())
798                } else {
799                    parent.root()
800                }
801            }
802            Name::Num(parent, _) => parent.root(),
803        }
804    }
805    /// Return the parent name (prefix with last component removed).
806    pub fn prefix(&self) -> Name {
807        match self {
808            Name::Anonymous => Name::Anonymous,
809            Name::Str(parent, _) | Name::Num(parent, _) => *parent.clone(),
810        }
811    }
812    /// Check whether this name has `prefix` as a (strict) prefix.
813    ///
814    /// `Nat.add.comm.has_prefix(Nat)` is `true`.
815    pub fn has_prefix(&self, prefix: &Name) -> bool {
816        if self == prefix {
817            return false;
818        }
819        let mut current = self;
820        loop {
821            match current {
822                Name::Anonymous => return false,
823                Name::Str(parent, _) | Name::Num(parent, _) => {
824                    if parent.as_ref() == prefix {
825                        return true;
826                    }
827                    current = parent;
828                }
829            }
830        }
831    }
832    /// Collect all components from root to leaf.
833    ///
834    /// Returns a vector of `(is_num, string_or_num)` pairs.
835    pub fn components(&self) -> Vec<String> {
836        let mut comps = Vec::new();
837        let mut current = self;
838        loop {
839            match current {
840                Name::Anonymous => break,
841                Name::Str(parent, s) => {
842                    comps.push(s.clone());
843                    current = parent;
844                }
845                Name::Num(parent, n) => {
846                    comps.push(n.to_string());
847                    current = parent;
848                }
849            }
850        }
851        comps.reverse();
852        comps
853    }
854    /// Reconstruct a `Name` from a list of string components.
855    ///
856    /// Numeric strings are converted to `Num` components.
857    pub fn from_components(comps: &[String]) -> Self {
858        let mut name = Name::Anonymous;
859        for comp in comps {
860            if let Ok(n) = comp.parse::<u64>() {
861                name = name.append_num(n);
862            } else {
863                name = name.append_str(comp.as_str());
864            }
865        }
866        name
867    }
868    /// Replace the last string component with `new_last`.
869    ///
870    /// If the name ends in a numeric component, appends `new_last` instead.
871    pub fn replace_last(self, new_last: impl Into<String>) -> Self {
872        match self {
873            Name::Anonymous => Name::str(new_last),
874            Name::Str(parent, _) => Name::Str(parent, new_last.into()),
875            Name::Num(parent, _) => Name::Str(parent, new_last.into()),
876        }
877    }
878    /// Produce a "fresh" version of this name by appending a suffix number.
879    ///
880    /// Used to avoid name collisions during elaboration.
881    pub fn freshen(self, suffix: u64) -> Self {
882        self.append_num(suffix)
883    }
884    /// Check whether this name is in the given namespace.
885    ///
886    /// A name is in namespace `ns` if it has `ns` as a strict prefix.
887    pub fn in_namespace(&self, ns: &Name) -> bool {
888        self.has_prefix(ns)
889    }
890    /// Append a suffix string to this name.
891    pub fn with_suffix(self, suffix: impl Into<String>) -> Self {
892        self.append_str(suffix)
893    }
894    /// Convert to a string suitable for use as a Rust identifier.
895    ///
896    /// Dots and special characters are replaced with underscores.
897    pub fn to_ident_string(&self) -> String {
898        self.to_string()
899            .chars()
900            .map(|c| {
901                if c.is_alphanumeric() || c == '_' {
902                    c
903                } else {
904                    '_'
905                }
906            })
907            .collect()
908    }
909    /// Return a new name with the given prefix prepended.
910    pub fn prepend(self, prefix: Name) -> Self {
911        let comps = self.components();
912        let mut name = prefix;
913        for comp in comps {
914            if let Ok(n) = comp.parse::<u64>() {
915                name = name.append_num(n);
916            } else {
917                name = name.append_str(comp);
918            }
919        }
920        name
921    }
922    /// Check whether this name is a string name (last component is a string).
923    pub fn is_str_name(&self) -> bool {
924        matches!(self, Name::Str(_, _))
925    }
926    /// Check whether this name is a numeric name (last component is a number).
927    pub fn is_num_name(&self) -> bool {
928        matches!(self, Name::Num(_, _))
929    }
930}
931/// A bidirectional mapping between names and numeric IDs.
932#[allow(dead_code)]
933pub struct NameMapping {
934    name_to_id: std::collections::HashMap<String, u32>,
935    id_to_name: std::collections::HashMap<u32, String>,
936    next_id: u32,
937}
938#[allow(dead_code)]
939impl NameMapping {
940    /// Creates an empty name mapping.
941    pub fn new() -> Self {
942        Self {
943            name_to_id: std::collections::HashMap::new(),
944            id_to_name: std::collections::HashMap::new(),
945            next_id: 0,
946        }
947    }
948    /// Registers `name` and returns its ID (or the existing ID).
949    pub fn register(&mut self, name: impl Into<String>) -> u32 {
950        let name = name.into();
951        if let Some(&id) = self.name_to_id.get(&name) {
952            return id;
953        }
954        let id = self.next_id;
955        self.next_id += 1;
956        self.name_to_id.insert(name.clone(), id);
957        self.id_to_name.insert(id, name);
958        id
959    }
960    /// Returns the ID for `name`, or `None`.
961    pub fn id_of(&self, name: &str) -> Option<u32> {
962        self.name_to_id.get(name).copied()
963    }
964    /// Returns the name for `id`, or `None`.
965    pub fn name_of(&self, id: u32) -> Option<&str> {
966        self.id_to_name.get(&id).map(|s| s.as_str())
967    }
968    /// Returns the total number of registered names.
969    pub fn len(&self) -> usize {
970        self.name_to_id.len()
971    }
972    /// Returns `true` if empty.
973    pub fn is_empty(&self) -> bool {
974        self.name_to_id.is_empty()
975    }
976}
977/// A key-value store for diagnostic metadata.
978#[allow(dead_code)]
979pub struct DiagMeta {
980    pub(super) entries: Vec<(String, String)>,
981}
982#[allow(dead_code)]
983impl DiagMeta {
984    /// Creates an empty metadata store.
985    pub fn new() -> Self {
986        Self {
987            entries: Vec::new(),
988        }
989    }
990    /// Adds a key-value pair.
991    pub fn add(&mut self, key: impl Into<String>, val: impl Into<String>) {
992        self.entries.push((key.into(), val.into()));
993    }
994    /// Returns the value for `key`, or `None`.
995    pub fn get(&self, key: &str) -> Option<&str> {
996        self.entries
997            .iter()
998            .find(|(k, _)| k == key)
999            .map(|(_, v)| v.as_str())
1000    }
1001    /// Returns the number of entries.
1002    pub fn len(&self) -> usize {
1003        self.entries.len()
1004    }
1005    /// Returns `true` if empty.
1006    pub fn is_empty(&self) -> bool {
1007        self.entries.is_empty()
1008    }
1009}
1010/// A simple sparse bit set.
1011#[allow(dead_code)]
1012pub struct SparseBitSet {
1013    words: Vec<u64>,
1014}
1015#[allow(dead_code)]
1016impl SparseBitSet {
1017    /// Creates a new bit set that can hold at least `capacity` bits.
1018    pub fn new(capacity: usize) -> Self {
1019        let words = (capacity + 63) / 64;
1020        Self {
1021            words: vec![0u64; words],
1022        }
1023    }
1024    /// Sets bit `i`.
1025    pub fn set(&mut self, i: usize) {
1026        let word = i / 64;
1027        let bit = i % 64;
1028        if word < self.words.len() {
1029            self.words[word] |= 1u64 << bit;
1030        }
1031    }
1032    /// Clears bit `i`.
1033    pub fn clear(&mut self, i: usize) {
1034        let word = i / 64;
1035        let bit = i % 64;
1036        if word < self.words.len() {
1037            self.words[word] &= !(1u64 << bit);
1038        }
1039    }
1040    /// Returns `true` if bit `i` is set.
1041    pub fn get(&self, i: usize) -> bool {
1042        let word = i / 64;
1043        let bit = i % 64;
1044        self.words.get(word).is_some_and(|w| w & (1u64 << bit) != 0)
1045    }
1046    /// Returns the number of set bits.
1047    pub fn count_ones(&self) -> u32 {
1048        self.words.iter().map(|w| w.count_ones()).sum()
1049    }
1050    /// Returns the union with another bit set.
1051    pub fn union(&self, other: &SparseBitSet) -> SparseBitSet {
1052        let len = self.words.len().max(other.words.len());
1053        let mut result = SparseBitSet {
1054            words: vec![0u64; len],
1055        };
1056        for i in 0..self.words.len() {
1057            result.words[i] |= self.words[i];
1058        }
1059        for i in 0..other.words.len() {
1060            result.words[i] |= other.words[i];
1061        }
1062        result
1063    }
1064}
1065/// A set of names with fast membership testing.
1066#[allow(dead_code)]
1067pub struct NameSetExt {
1068    inner: std::collections::HashSet<String>,
1069}
1070#[allow(dead_code)]
1071impl NameSetExt {
1072    /// Creates an empty name set.
1073    pub fn new() -> Self {
1074        Self {
1075            inner: std::collections::HashSet::new(),
1076        }
1077    }
1078    /// Inserts `name`.
1079    pub fn insert(&mut self, name: impl Into<String>) {
1080        self.inner.insert(name.into());
1081    }
1082    /// Returns `true` if `name` is in the set.
1083    pub fn contains(&self, name: &str) -> bool {
1084        self.inner.contains(name)
1085    }
1086    /// Removes `name`.
1087    pub fn remove(&mut self, name: &str) {
1088        self.inner.remove(name);
1089    }
1090    /// Returns the number of names.
1091    pub fn len(&self) -> usize {
1092        self.inner.len()
1093    }
1094    /// Returns `true` if empty.
1095    pub fn is_empty(&self) -> bool {
1096        self.inner.is_empty()
1097    }
1098    /// Returns the union with another set.
1099    pub fn union(&self, other: &NameSetExt) -> NameSetExt {
1100        let mut result = NameSetExt::new();
1101        for n in &self.inner {
1102            result.insert(n.as_str());
1103        }
1104        for n in &other.inner {
1105            result.insert(n.as_str());
1106        }
1107        result
1108    }
1109    /// Returns the intersection with another set.
1110    pub fn intersect(&self, other: &NameSetExt) -> NameSetExt {
1111        let mut result = NameSetExt::new();
1112        for n in &self.inner {
1113            if other.contains(n) {
1114                result.insert(n.as_str());
1115            }
1116        }
1117        result
1118    }
1119}
1120/// A simple stack-based scope tracker.
1121#[allow(dead_code)]
1122pub struct ScopeStack {
1123    names: Vec<String>,
1124}
1125#[allow(dead_code)]
1126impl ScopeStack {
1127    /// Creates a new empty scope stack.
1128    pub fn new() -> Self {
1129        Self { names: Vec::new() }
1130    }
1131    /// Pushes a scope name.
1132    pub fn push(&mut self, name: impl Into<String>) {
1133        self.names.push(name.into());
1134    }
1135    /// Pops the current scope.
1136    pub fn pop(&mut self) -> Option<String> {
1137        self.names.pop()
1138    }
1139    /// Returns the current (innermost) scope name, or `None`.
1140    pub fn current(&self) -> Option<&str> {
1141        self.names.last().map(|s| s.as_str())
1142    }
1143    /// Returns the depth of the scope stack.
1144    pub fn depth(&self) -> usize {
1145        self.names.len()
1146    }
1147    /// Returns `true` if the stack is empty.
1148    pub fn is_empty(&self) -> bool {
1149        self.names.is_empty()
1150    }
1151    /// Returns the full path as a dot-separated string.
1152    pub fn path(&self) -> String {
1153        self.names.join(".")
1154    }
1155}
1156/// A trie (prefix tree) for efficient prefix search over names.
1157#[allow(dead_code)]
1158pub struct NameTrieExt {
1159    children: std::collections::HashMap<char, NameTrieExt>,
1160    terminal: bool,
1161    name: Option<String>,
1162}
1163#[allow(dead_code)]
1164impl NameTrieExt {
1165    /// Creates an empty trie.
1166    pub fn new() -> Self {
1167        Self {
1168            children: std::collections::HashMap::new(),
1169            terminal: false,
1170            name: None,
1171        }
1172    }
1173    /// Inserts a name into the trie.
1174    pub fn insert(&mut self, name: &str) {
1175        let mut node = self;
1176        for c in name.chars() {
1177            node = node.children.entry(c).or_default();
1178        }
1179        node.terminal = true;
1180        node.name = Some(name.to_string());
1181    }
1182    /// Returns `true` if `name` is in the trie.
1183    pub fn contains(&self, name: &str) -> bool {
1184        let mut node = self;
1185        for c in name.chars() {
1186            match node.children.get(&c) {
1187                Some(n) => node = n,
1188                None => return false,
1189            }
1190        }
1191        node.terminal
1192    }
1193    /// Collects all names with the given prefix.
1194    pub fn with_prefix(&self, prefix: &str) -> Vec<String> {
1195        let mut node = self;
1196        for c in prefix.chars() {
1197            match node.children.get(&c) {
1198                Some(n) => node = n,
1199                None => return Vec::new(),
1200            }
1201        }
1202        let mut results = Vec::new();
1203        node.collect_all(&mut results);
1204        results
1205    }
1206    fn collect_all(&self, out: &mut Vec<String>) {
1207        if let Some(ref n) = self.name {
1208            out.push(n.clone());
1209        }
1210        for child in self.children.values() {
1211            let c: &NameTrieExt = child;
1212            c.collect_all(out);
1213        }
1214    }
1215}
1216/// A simple event counter with named events.
1217#[allow(dead_code)]
1218pub struct EventCounter {
1219    counts: std::collections::HashMap<String, u64>,
1220}
1221#[allow(dead_code)]
1222impl EventCounter {
1223    /// Creates a new empty counter.
1224    pub fn new() -> Self {
1225        Self {
1226            counts: std::collections::HashMap::new(),
1227        }
1228    }
1229    /// Increments the counter for `event`.
1230    pub fn inc(&mut self, event: &str) {
1231        *self.counts.entry(event.to_string()).or_insert(0) += 1;
1232    }
1233    /// Adds `n` to the counter for `event`.
1234    pub fn add(&mut self, event: &str, n: u64) {
1235        *self.counts.entry(event.to_string()).or_insert(0) += n;
1236    }
1237    /// Returns the count for `event`.
1238    pub fn get(&self, event: &str) -> u64 {
1239        self.counts.get(event).copied().unwrap_or(0)
1240    }
1241    /// Returns the total count across all events.
1242    pub fn total(&self) -> u64 {
1243        self.counts.values().sum()
1244    }
1245    /// Resets all counters.
1246    pub fn reset(&mut self) {
1247        self.counts.clear();
1248    }
1249    /// Returns all event names.
1250    pub fn event_names(&self) -> Vec<&str> {
1251        self.counts.keys().map(|s| s.as_str()).collect()
1252    }
1253}
1254/// A set of `Name` values.
1255///
1256/// Wraps `HashSet<Name>` for convenient use in the elaborator.
1257#[derive(Debug, Clone, Default)]
1258pub struct NameSet {
1259    pub(super) inner: HashSet<Name>,
1260}
1261impl NameSet {
1262    /// Create an empty `NameSet`.
1263    pub fn new() -> Self {
1264        Self {
1265            inner: HashSet::new(),
1266        }
1267    }
1268    /// Insert a name. Returns `true` if it was newly inserted.
1269    pub fn insert(&mut self, name: Name) -> bool {
1270        self.inner.insert(name)
1271    }
1272    /// Remove a name. Returns `true` if it was present.
1273    pub fn remove(&mut self, name: &Name) -> bool {
1274        self.inner.remove(name)
1275    }
1276    /// Check whether the set contains `name`.
1277    pub fn contains(&self, name: &Name) -> bool {
1278        self.inner.contains(name)
1279    }
1280    /// Number of names in the set.
1281    pub fn len(&self) -> usize {
1282        self.inner.len()
1283    }
1284    /// Returns `true` if the set is empty.
1285    pub fn is_empty(&self) -> bool {
1286        self.inner.is_empty()
1287    }
1288    /// Iterate over all names.
1289    pub fn iter(&self) -> impl Iterator<Item = &Name> {
1290        self.inner.iter()
1291    }
1292    /// Compute the union with another `NameSet`.
1293    pub fn union(&self, other: &NameSet) -> NameSet {
1294        NameSet {
1295            inner: self.inner.union(&other.inner).cloned().collect(),
1296        }
1297    }
1298    /// Compute the intersection with another `NameSet`.
1299    pub fn intersection(&self, other: &NameSet) -> NameSet {
1300        NameSet {
1301            inner: self.inner.intersection(&other.inner).cloned().collect(),
1302        }
1303    }
1304    /// Compute the difference `self \ other`.
1305    pub fn difference(&self, other: &NameSet) -> NameSet {
1306        NameSet {
1307            inner: self.inner.difference(&other.inner).cloned().collect(),
1308        }
1309    }
1310    /// Filter to names in a given namespace.
1311    pub fn in_namespace(&self, ns: &Name) -> NameSet {
1312        NameSet {
1313            inner: self
1314                .inner
1315                .iter()
1316                .filter(|n| n.has_prefix(ns))
1317                .cloned()
1318                .collect(),
1319        }
1320    }
1321    /// Convert to a sorted vector.
1322    pub fn to_sorted_vec(&self) -> Vec<Name> {
1323        let mut v: Vec<Name> = self.inner.iter().cloned().collect();
1324        v.sort();
1325        v
1326    }
1327}
1328/// A key-value annotation table for arbitrary metadata.
1329#[allow(dead_code)]
1330pub struct AnnotationTable {
1331    map: std::collections::HashMap<String, Vec<String>>,
1332}
1333#[allow(dead_code)]
1334impl AnnotationTable {
1335    /// Creates an empty annotation table.
1336    pub fn new() -> Self {
1337        Self {
1338            map: std::collections::HashMap::new(),
1339        }
1340    }
1341    /// Adds an annotation value for the given key.
1342    pub fn annotate(&mut self, key: impl Into<String>, val: impl Into<String>) {
1343        self.map.entry(key.into()).or_default().push(val.into());
1344    }
1345    /// Returns all annotations for `key`.
1346    pub fn get_all(&self, key: &str) -> &[String] {
1347        self.map.get(key).map(|v| v.as_slice()).unwrap_or(&[])
1348    }
1349    /// Returns the number of distinct annotation keys.
1350    pub fn num_keys(&self) -> usize {
1351        self.map.len()
1352    }
1353    /// Returns `true` if the table has any annotations for `key`.
1354    pub fn has(&self, key: &str) -> bool {
1355        self.map.contains_key(key)
1356    }
1357}
1358/// A simple LRU cache backed by a linked list + hash map.
1359#[allow(dead_code)]
1360pub struct SimpleLruCache<K: std::hash::Hash + Eq + Clone, V: Clone> {
1361    capacity: usize,
1362    map: std::collections::HashMap<K, usize>,
1363    keys: Vec<K>,
1364    vals: Vec<V>,
1365    order: Vec<usize>,
1366}
1367#[allow(dead_code)]
1368impl<K: std::hash::Hash + Eq + Clone, V: Clone> SimpleLruCache<K, V> {
1369    /// Creates a new LRU cache with the given capacity.
1370    pub fn new(capacity: usize) -> Self {
1371        assert!(capacity > 0);
1372        Self {
1373            capacity,
1374            map: std::collections::HashMap::new(),
1375            keys: Vec::new(),
1376            vals: Vec::new(),
1377            order: Vec::new(),
1378        }
1379    }
1380    /// Inserts or updates a key-value pair.
1381    pub fn put(&mut self, key: K, val: V) {
1382        if let Some(&idx) = self.map.get(&key) {
1383            self.vals[idx] = val;
1384            self.order.retain(|&x| x != idx);
1385            self.order.insert(0, idx);
1386            return;
1387        }
1388        if self.keys.len() >= self.capacity {
1389            let evict_idx = *self
1390                .order
1391                .last()
1392                .expect("order list must be non-empty before eviction");
1393            self.map.remove(&self.keys[evict_idx]);
1394            self.order.pop();
1395            self.keys[evict_idx] = key.clone();
1396            self.vals[evict_idx] = val;
1397            self.map.insert(key, evict_idx);
1398            self.order.insert(0, evict_idx);
1399        } else {
1400            let idx = self.keys.len();
1401            self.keys.push(key.clone());
1402            self.vals.push(val);
1403            self.map.insert(key, idx);
1404            self.order.insert(0, idx);
1405        }
1406    }
1407    /// Returns a reference to the value for `key`, promoting it.
1408    pub fn get(&mut self, key: &K) -> Option<&V> {
1409        let idx = *self.map.get(key)?;
1410        self.order.retain(|&x| x != idx);
1411        self.order.insert(0, idx);
1412        Some(&self.vals[idx])
1413    }
1414    /// Returns the number of entries.
1415    pub fn len(&self) -> usize {
1416        self.keys.len()
1417    }
1418    /// Returns `true` if empty.
1419    pub fn is_empty(&self) -> bool {
1420        self.keys.is_empty()
1421    }
1422}
1423/// A slot that can hold a value, with lazy initialization.
1424#[allow(dead_code)]
1425pub struct Slot<T> {
1426    inner: Option<T>,
1427}
1428#[allow(dead_code)]
1429impl<T> Slot<T> {
1430    /// Creates an empty slot.
1431    pub fn empty() -> Self {
1432        Self { inner: None }
1433    }
1434    /// Fills the slot with `val`.  Panics if already filled.
1435    pub fn fill(&mut self, val: T) {
1436        assert!(self.inner.is_none(), "Slot: already filled");
1437        self.inner = Some(val);
1438    }
1439    /// Returns the slot's value, or `None`.
1440    pub fn get(&self) -> Option<&T> {
1441        self.inner.as_ref()
1442    }
1443    /// Returns `true` if the slot is filled.
1444    pub fn is_filled(&self) -> bool {
1445        self.inner.is_some()
1446    }
1447    /// Takes the value out of the slot.
1448    pub fn take(&mut self) -> Option<T> {
1449        self.inner.take()
1450    }
1451    /// Fills the slot if empty, returning a reference to the value.
1452    pub fn get_or_fill_with(&mut self, f: impl FnOnce() -> T) -> &T {
1453        if self.inner.is_none() {
1454            self.inner = Some(f());
1455        }
1456        self.inner
1457            .as_ref()
1458            .expect("inner value must be initialized before access")
1459    }
1460}
1461/// Generates fresh unique names.
1462#[allow(dead_code)]
1463pub struct NameGeneratorExt {
1464    prefix: String,
1465    counter: u64,
1466}
1467#[allow(dead_code)]
1468impl NameGeneratorExt {
1469    /// Creates a generator using the given prefix.
1470    pub fn new(prefix: impl Into<String>) -> Self {
1471        Self {
1472            prefix: prefix.into(),
1473            counter: 0,
1474        }
1475    }
1476    /// Returns the next fresh name.
1477    #[allow(clippy::should_implement_trait)]
1478    pub fn next(&mut self) -> String {
1479        let n = self.counter;
1480        self.counter += 1;
1481        format!("{}{}", self.prefix, n)
1482    }
1483    /// Returns the number of names generated.
1484    pub fn count(&self) -> u64 {
1485        self.counter
1486    }
1487    /// Resets the counter to zero.
1488    pub fn reset(&mut self) {
1489        self.counter = 0;
1490    }
1491}
1492/// A counted-access cache that tracks hit and miss statistics.
1493#[allow(dead_code)]
1494#[allow(missing_docs)]
1495pub struct StatCache<K: std::hash::Hash + Eq + Clone, V: Clone> {
1496    /// The inner LRU cache.
1497    pub inner: SimpleLruCache<K, V>,
1498    /// Number of cache hits.
1499    pub hits: u64,
1500    /// Number of cache misses.
1501    pub misses: u64,
1502}
1503#[allow(dead_code)]
1504impl<K: std::hash::Hash + Eq + Clone, V: Clone> StatCache<K, V> {
1505    /// Creates a new stat cache with the given capacity.
1506    pub fn new(capacity: usize) -> Self {
1507        Self {
1508            inner: SimpleLruCache::new(capacity),
1509            hits: 0,
1510            misses: 0,
1511        }
1512    }
1513    /// Performs a lookup, tracking hit/miss.
1514    pub fn get(&mut self, key: &K) -> Option<&V> {
1515        let result = self.inner.get(key);
1516        if result.is_some() {
1517            self.hits += 1;
1518        } else {
1519            self.misses += 1;
1520        }
1521        None
1522    }
1523    /// Inserts a key-value pair.
1524    pub fn put(&mut self, key: K, val: V) {
1525        self.inner.put(key, val);
1526    }
1527    /// Returns the hit rate.
1528    pub fn hit_rate(&self) -> f64 {
1529        let total = self.hits + self.misses;
1530        if total == 0 {
1531            return 0.0;
1532        }
1533        self.hits as f64 / total as f64
1534    }
1535}
1536/// Tracks the frequency of items.
1537#[allow(dead_code)]
1538pub struct FrequencyTable<T: std::hash::Hash + Eq + Clone> {
1539    counts: std::collections::HashMap<T, u64>,
1540}
1541#[allow(dead_code)]
1542impl<T: std::hash::Hash + Eq + Clone> FrequencyTable<T> {
1543    /// Creates a new empty frequency table.
1544    pub fn new() -> Self {
1545        Self {
1546            counts: std::collections::HashMap::new(),
1547        }
1548    }
1549    /// Records one occurrence of `item`.
1550    pub fn record(&mut self, item: T) {
1551        *self.counts.entry(item).or_insert(0) += 1;
1552    }
1553    /// Returns the frequency of `item`.
1554    pub fn freq(&self, item: &T) -> u64 {
1555        self.counts.get(item).copied().unwrap_or(0)
1556    }
1557    /// Returns the item with the highest frequency.
1558    pub fn most_frequent(&self) -> Option<(&T, u64)> {
1559        self.counts
1560            .iter()
1561            .max_by_key(|(_, &v)| v)
1562            .map(|(k, &v)| (k, v))
1563    }
1564    /// Returns the total number of recordings.
1565    pub fn total(&self) -> u64 {
1566        self.counts.values().sum()
1567    }
1568    /// Returns the number of distinct items.
1569    pub fn distinct(&self) -> usize {
1570        self.counts.len()
1571    }
1572}
1573/// A counter that dispenses monotonically increasing `TypedId` values.
1574#[allow(dead_code)]
1575pub struct IdDispenser<T> {
1576    next: u32,
1577    _phantom: std::marker::PhantomData<T>,
1578}
1579#[allow(dead_code)]
1580impl<T> IdDispenser<T> {
1581    /// Creates a new dispenser starting from zero.
1582    pub fn new() -> Self {
1583        Self {
1584            next: 0,
1585            _phantom: std::marker::PhantomData,
1586        }
1587    }
1588    /// Dispenses the next ID.
1589    #[allow(clippy::should_implement_trait)]
1590    pub fn next(&mut self) -> TypedId<T> {
1591        let id = TypedId::new(self.next);
1592        self.next += 1;
1593        id
1594    }
1595    /// Returns the number of IDs dispensed.
1596    pub fn count(&self) -> u32 {
1597        self.next
1598    }
1599}
1600/// A dot-separated qualified name (e.g. `Nat.succ`).
1601#[allow(dead_code)]
1602#[allow(missing_docs)]
1603pub struct QualifiedNameExt {
1604    /// Component parts of the name.
1605    pub parts: Vec<String>,
1606}
1607#[allow(dead_code)]
1608impl QualifiedNameExt {
1609    /// Creates a qualified name from a dot-separated string.
1610    pub fn from_dot_str(s: &str) -> Self {
1611        s.parse().unwrap_or_else(|_| unreachable!())
1612    }
1613    /// Creates a single-component name.
1614    pub fn simple(name: impl Into<String>) -> Self {
1615        Self {
1616            parts: vec![name.into()],
1617        }
1618    }
1619    /// Returns the last component (unqualified name).
1620    pub fn unqualified(&self) -> &str {
1621        self.parts.last().map(|s| s.as_str()).unwrap_or("")
1622    }
1623    /// Returns the namespace (all but the last component), or `None`.
1624    pub fn namespace(&self) -> Option<QualifiedNameExt> {
1625        if self.parts.len() <= 1 {
1626            return None;
1627        }
1628        let parts = self.parts[..self.parts.len() - 1].to_vec();
1629        Some(QualifiedNameExt { parts })
1630    }
1631    /// Returns `true` if this name is a sub-name of `other`.
1632    pub fn is_sub_of(&self, other: &QualifiedNameExt) -> bool {
1633        self.parts.starts_with(&other.parts)
1634    }
1635    /// Returns the number of components.
1636    pub fn depth(&self) -> usize {
1637        self.parts.len()
1638    }
1639}
1640/// A memoized computation slot that stores a cached value.
1641#[allow(dead_code)]
1642pub struct MemoSlot<T: Clone> {
1643    cached: Option<T>,
1644}
1645#[allow(dead_code)]
1646impl<T: Clone> MemoSlot<T> {
1647    /// Creates an uncomputed memo slot.
1648    pub fn new() -> Self {
1649        Self { cached: None }
1650    }
1651    /// Returns the cached value, computing it with `f` if absent.
1652    pub fn get_or_compute(&mut self, f: impl FnOnce() -> T) -> &T {
1653        if self.cached.is_none() {
1654            self.cached = Some(f());
1655        }
1656        self.cached
1657            .as_ref()
1658            .expect("cached value must be initialized before access")
1659    }
1660    /// Invalidates the cached value.
1661    pub fn invalidate(&mut self) {
1662        self.cached = None;
1663    }
1664    /// Returns `true` if the value has been computed.
1665    pub fn is_cached(&self) -> bool {
1666        self.cached.is_some()
1667    }
1668}