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