Skip to main content

oxilean_kernel/declaration/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use crate::reduce::ReducibilityHint;
6use crate::{Expr, Level, Name};
7
8use std::collections::{HashMap, HashSet, VecDeque};
9
10/// A simple LIFO work queue.
11#[allow(dead_code)]
12pub struct WorkStack<T> {
13    items: Vec<T>,
14}
15#[allow(dead_code)]
16impl<T> WorkStack<T> {
17    /// Creates a new empty stack.
18    pub fn new() -> Self {
19        Self { items: Vec::new() }
20    }
21    /// Pushes a work item.
22    pub fn push(&mut self, item: T) {
23        self.items.push(item);
24    }
25    /// Pops the next work item.
26    pub fn pop(&mut self) -> Option<T> {
27        self.items.pop()
28    }
29    /// Returns `true` if empty.
30    pub fn is_empty(&self) -> bool {
31        self.items.is_empty()
32    }
33    /// Returns the number of pending work items.
34    pub fn len(&self) -> usize {
35        self.items.len()
36    }
37}
38/// A memoized computation slot that stores a cached value.
39#[allow(dead_code)]
40pub struct MemoSlot<T: Clone> {
41    cached: Option<T>,
42}
43#[allow(dead_code)]
44impl<T: Clone> MemoSlot<T> {
45    /// Creates an uncomputed memo slot.
46    pub fn new() -> Self {
47        Self { cached: None }
48    }
49    /// Returns the cached value, computing it with `f` if absent.
50    pub fn get_or_compute(&mut self, f: impl FnOnce() -> T) -> &T {
51        if self.cached.is_none() {
52            self.cached = Some(f());
53        }
54        self.cached
55            .as_ref()
56            .expect("cached value must be initialized before access")
57    }
58    /// Invalidates the cached value.
59    pub fn invalidate(&mut self) {
60        self.cached = None;
61    }
62    /// Returns `true` if the value has been computed.
63    pub fn is_cached(&self) -> bool {
64        self.cached.is_some()
65    }
66}
67/// Base constant value shared by all declaration types.
68#[derive(Clone, Debug, PartialEq)]
69pub struct ConstantVal {
70    /// Declaration name.
71    pub name: Name,
72    /// Universe level parameters.
73    pub level_params: Vec<Name>,
74    /// Type of the constant.
75    pub ty: Expr,
76}
77/// An index that maps declaration names to their positions.
78#[allow(dead_code)]
79pub struct DeclIndex {
80    map: std::collections::HashMap<String, usize>,
81}
82#[allow(dead_code)]
83impl DeclIndex {
84    /// Creates an empty declaration index.
85    pub fn new() -> Self {
86        Self {
87            map: std::collections::HashMap::new(),
88        }
89    }
90    /// Inserts a name-position pair.
91    pub fn insert(&mut self, name: impl Into<String>, pos: usize) {
92        self.map.insert(name.into(), pos);
93    }
94    /// Returns the position of `name`, or `None`.
95    pub fn get(&self, name: &str) -> Option<usize> {
96        self.map.get(name).copied()
97    }
98    /// Returns the number of indexed declarations.
99    pub fn len(&self) -> usize {
100        self.map.len()
101    }
102    /// Returns `true` if empty.
103    pub fn is_empty(&self) -> bool {
104        self.map.is_empty()
105    }
106    /// Returns all names.
107    pub fn names(&self) -> Vec<&str> {
108        self.map.keys().map(|s| s.as_str()).collect()
109    }
110}
111/// Axiom declaration value.
112#[derive(Clone, Debug, PartialEq)]
113pub struct AxiomVal {
114    /// Common fields.
115    pub common: ConstantVal,
116    /// Whether this axiom is unsafe.
117    pub is_unsafe: bool,
118}
119/// Which quotient component a declaration represents.
120#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
121pub enum QuotKind {
122    /// `Quot` type itself.
123    Type,
124    /// `Quot.mk` constructor.
125    Mk,
126    /// `Quot.lift` eliminator.
127    Lift,
128    /// `Quot.ind` induction principle.
129    Ind,
130}
131/// Constructor declaration value.
132#[derive(Clone, Debug, PartialEq)]
133pub struct ConstructorVal {
134    /// Common fields.
135    pub common: ConstantVal,
136    /// Name of parent inductive type.
137    pub induct: Name,
138    /// Constructor index (position in declaration order).
139    pub cidx: u32,
140    /// Number of inductive parameters.
141    pub num_params: u32,
142    /// Number of fields (arity - nparams).
143    pub num_fields: u32,
144    /// Whether this is unsafe.
145    pub is_unsafe: bool,
146}
147/// A simple event counter with named events.
148#[allow(dead_code)]
149pub struct EventCounter {
150    counts: std::collections::HashMap<String, u64>,
151}
152#[allow(dead_code)]
153impl EventCounter {
154    /// Creates a new empty counter.
155    pub fn new() -> Self {
156        Self {
157            counts: std::collections::HashMap::new(),
158        }
159    }
160    /// Increments the counter for `event`.
161    pub fn inc(&mut self, event: &str) {
162        *self.counts.entry(event.to_string()).or_insert(0) += 1;
163    }
164    /// Adds `n` to the counter for `event`.
165    pub fn add(&mut self, event: &str, n: u64) {
166        *self.counts.entry(event.to_string()).or_insert(0) += n;
167    }
168    /// Returns the count for `event`.
169    pub fn get(&self, event: &str) -> u64 {
170        self.counts.get(event).copied().unwrap_or(0)
171    }
172    /// Returns the total count across all events.
173    pub fn total(&self) -> u64 {
174        self.counts.values().sum()
175    }
176    /// Resets all counters.
177    pub fn reset(&mut self) {
178        self.counts.clear();
179    }
180    /// Returns all event names.
181    pub fn event_names(&self) -> Vec<&str> {
182        self.counts.keys().map(|s| s.as_str()).collect()
183    }
184}
185/// Theorem declaration value.
186#[derive(Clone, Debug, PartialEq)]
187pub struct TheoremVal {
188    /// Common fields.
189    pub common: ConstantVal,
190    /// Proof term.
191    pub value: Expr,
192    /// Names in mutual declaration group.
193    pub all: Vec<Name>,
194}
195/// Recursor (eliminator) declaration value.
196#[derive(Clone, Debug, PartialEq)]
197pub struct RecursorVal {
198    /// Common fields.
199    pub common: ConstantVal,
200    /// All inductive types in mutual declaration.
201    pub all: Vec<Name>,
202    /// Number of parameters.
203    pub num_params: u32,
204    /// Number of indices.
205    pub num_indices: u32,
206    /// Number of motive arguments.
207    pub num_motives: u32,
208    /// Number of minor premises (one per constructor).
209    pub num_minors: u32,
210    /// Reduction rules (one per constructor).
211    pub rules: Vec<RecursorRule>,
212    /// Whether this supports K-like reduction.
213    pub k: bool,
214    /// Whether this is unsafe.
215    pub is_unsafe: bool,
216}
217impl RecursorVal {
218    /// Get the index of the major premise in the recursor's arguments.
219    ///
220    /// The major premise is the argument being eliminated.
221    /// Position: nparams + nmotives + nminors + nindices
222    pub fn get_major_idx(&self) -> u32 {
223        self.num_params + self.num_motives + self.num_minors + self.num_indices
224    }
225    /// Get the total number of arguments before the major premise.
226    pub fn get_first_index_idx(&self) -> u32 {
227        self.num_params + self.num_motives + self.num_minors
228    }
229    /// Find the reduction rule for a given constructor.
230    pub fn get_rule(&self, ctor: &Name) -> Option<&RecursorRule> {
231        self.rules.iter().find(|r| &r.ctor == ctor)
232    }
233}
234/// A simple stack-based scope tracker.
235#[allow(dead_code)]
236pub struct ScopeStack {
237    names: Vec<String>,
238}
239#[allow(dead_code)]
240impl ScopeStack {
241    /// Creates a new empty scope stack.
242    pub fn new() -> Self {
243        Self { names: Vec::new() }
244    }
245    /// Pushes a scope name.
246    pub fn push(&mut self, name: impl Into<String>) {
247        self.names.push(name.into());
248    }
249    /// Pops the current scope.
250    pub fn pop(&mut self) -> Option<String> {
251        self.names.pop()
252    }
253    /// Returns the current (innermost) scope name, or `None`.
254    pub fn current(&self) -> Option<&str> {
255        self.names.last().map(|s| s.as_str())
256    }
257    /// Returns the depth of the scope stack.
258    pub fn depth(&self) -> usize {
259        self.names.len()
260    }
261    /// Returns `true` if the stack is empty.
262    pub fn is_empty(&self) -> bool {
263        self.names.is_empty()
264    }
265    /// Returns the full path as a dot-separated string.
266    pub fn path(&self) -> String {
267        self.names.join(".")
268    }
269}
270/// A key-value annotation table for arbitrary metadata.
271#[allow(dead_code)]
272pub struct AnnotationTable {
273    map: std::collections::HashMap<String, Vec<String>>,
274}
275#[allow(dead_code)]
276impl AnnotationTable {
277    /// Creates an empty annotation table.
278    pub fn new() -> Self {
279        Self {
280            map: std::collections::HashMap::new(),
281        }
282    }
283    /// Adds an annotation value for the given key.
284    pub fn annotate(&mut self, key: impl Into<String>, val: impl Into<String>) {
285        self.map.entry(key.into()).or_default().push(val.into());
286    }
287    /// Returns all annotations for `key`.
288    pub fn get_all(&self, key: &str) -> &[String] {
289        self.map.get(key).map(|v| v.as_slice()).unwrap_or(&[])
290    }
291    /// Returns the number of distinct annotation keys.
292    pub fn num_keys(&self) -> usize {
293        self.map.len()
294    }
295    /// Returns `true` if the table has any annotations for `key`.
296    pub fn has(&self, key: &str) -> bool {
297        self.map.contains_key(key)
298    }
299}
300/// A clock that measures elapsed time in a loop.
301#[allow(dead_code)]
302pub struct LoopClock {
303    start: std::time::Instant,
304    iters: u64,
305}
306#[allow(dead_code)]
307impl LoopClock {
308    /// Starts the clock.
309    pub fn start() -> Self {
310        Self {
311            start: std::time::Instant::now(),
312            iters: 0,
313        }
314    }
315    /// Records one iteration.
316    pub fn tick(&mut self) {
317        self.iters += 1;
318    }
319    /// Returns the elapsed time in microseconds.
320    pub fn elapsed_us(&self) -> f64 {
321        self.start.elapsed().as_secs_f64() * 1e6
322    }
323    /// Returns the average microseconds per iteration.
324    pub fn avg_us_per_iter(&self) -> f64 {
325        if self.iters == 0 {
326            return 0.0;
327        }
328        self.elapsed_us() / self.iters as f64
329    }
330    /// Returns the number of iterations.
331    pub fn iters(&self) -> u64 {
332        self.iters
333    }
334}
335/// A simple sparse bit set.
336#[allow(dead_code)]
337pub struct SparseBitSet {
338    words: Vec<u64>,
339}
340#[allow(dead_code)]
341impl SparseBitSet {
342    /// Creates a new bit set that can hold at least `capacity` bits.
343    pub fn new(capacity: usize) -> Self {
344        let words = (capacity + 63) / 64;
345        Self {
346            words: vec![0u64; words],
347        }
348    }
349    /// Sets bit `i`.
350    pub fn set(&mut self, i: usize) {
351        let word = i / 64;
352        let bit = i % 64;
353        if word < self.words.len() {
354            self.words[word] |= 1u64 << bit;
355        }
356    }
357    /// Clears bit `i`.
358    pub fn clear(&mut self, i: usize) {
359        let word = i / 64;
360        let bit = i % 64;
361        if word < self.words.len() {
362            self.words[word] &= !(1u64 << bit);
363        }
364    }
365    /// Returns `true` if bit `i` is set.
366    pub fn get(&self, i: usize) -> bool {
367        let word = i / 64;
368        let bit = i % 64;
369        self.words.get(word).is_some_and(|w| w & (1u64 << bit) != 0)
370    }
371    /// Returns the number of set bits.
372    pub fn count_ones(&self) -> u32 {
373        self.words.iter().map(|w| w.count_ones()).sum()
374    }
375    /// Returns the union with another bit set.
376    pub fn union(&self, other: &SparseBitSet) -> SparseBitSet {
377        let len = self.words.len().max(other.words.len());
378        let mut result = SparseBitSet {
379            words: vec![0u64; len],
380        };
381        for i in 0..self.words.len() {
382            result.words[i] |= self.words[i];
383        }
384        for i in 0..other.words.len() {
385            result.words[i] |= other.words[i];
386        }
387        result
388    }
389}
390/// A counted-access cache that tracks hit and miss statistics.
391#[allow(dead_code)]
392#[allow(missing_docs)]
393pub struct StatCache<K: std::hash::Hash + Eq + Clone, V: Clone> {
394    /// The inner LRU cache.
395    pub inner: SimpleLruCache<K, V>,
396    /// Number of cache hits.
397    pub hits: u64,
398    /// Number of cache misses.
399    pub misses: u64,
400}
401#[allow(dead_code)]
402impl<K: std::hash::Hash + Eq + Clone, V: Clone> StatCache<K, V> {
403    /// Creates a new stat cache with the given capacity.
404    pub fn new(capacity: usize) -> Self {
405        Self {
406            inner: SimpleLruCache::new(capacity),
407            hits: 0,
408            misses: 0,
409        }
410    }
411    /// Performs a lookup, tracking hit/miss.
412    pub fn get(&mut self, key: &K) -> Option<&V> {
413        let result = self.inner.get(key);
414        if result.is_some() {
415            self.hits += 1;
416        } else {
417            self.misses += 1;
418        }
419        None
420    }
421    /// Inserts a key-value pair.
422    pub fn put(&mut self, key: K, val: V) {
423        self.inner.put(key, val);
424    }
425    /// Returns the hit rate.
426    pub fn hit_rate(&self) -> f64 {
427        let total = self.hits + self.misses;
428        if total == 0 {
429            return 0.0;
430        }
431        self.hits as f64 / total as f64
432    }
433}
434/// A slot that can hold a value, with lazy initialization.
435#[allow(dead_code)]
436pub struct Slot<T> {
437    inner: Option<T>,
438}
439#[allow(dead_code)]
440impl<T> Slot<T> {
441    /// Creates an empty slot.
442    pub fn empty() -> Self {
443        Self { inner: None }
444    }
445    /// Fills the slot with `val`.  Panics if already filled.
446    pub fn fill(&mut self, val: T) {
447        assert!(self.inner.is_none(), "Slot: already filled");
448        self.inner = Some(val);
449    }
450    /// Returns the slot's value, or `None`.
451    pub fn get(&self) -> Option<&T> {
452        self.inner.as_ref()
453    }
454    /// Returns `true` if the slot is filled.
455    pub fn is_filled(&self) -> bool {
456        self.inner.is_some()
457    }
458    /// Takes the value out of the slot.
459    pub fn take(&mut self) -> Option<T> {
460        self.inner.take()
461    }
462    /// Fills the slot if empty, returning a reference to the value.
463    pub fn get_or_fill_with(&mut self, f: impl FnOnce() -> T) -> &T {
464        if self.inner.is_none() {
465            self.inner = Some(f());
466        }
467        self.inner
468            .as_ref()
469            .expect("inner value must be initialized before access")
470    }
471}
472/// A pair of values useful for before/after comparisons.
473#[allow(dead_code)]
474#[allow(missing_docs)]
475pub struct BeforeAfter<T> {
476    /// Value before the transformation.
477    pub before: T,
478    /// Value after the transformation.
479    pub after: T,
480}
481#[allow(dead_code)]
482impl<T: PartialEq> BeforeAfter<T> {
483    /// Creates a new before/after pair.
484    pub fn new(before: T, after: T) -> Self {
485        Self { before, after }
486    }
487    /// Returns `true` if before equals after (no change).
488    pub fn unchanged(&self) -> bool {
489        self.before == self.after
490    }
491}
492/// A single recursor reduction rule.
493///
494/// When the recursor's major premise is headed by constructor `ctor`,
495/// the recursor reduces using the `rhs` expression.
496#[derive(Clone, Debug, PartialEq)]
497pub struct RecursorRule {
498    /// Constructor this rule applies to.
499    pub ctor: Name,
500    /// Number of fields for this constructor.
501    pub nfields: u32,
502    /// Right-hand side of the reduction rule.
503    pub rhs: Expr,
504}
505/// A monotonic timestamp in microseconds.
506#[allow(dead_code)]
507#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
508pub struct Timestamp(u64);
509#[allow(dead_code)]
510impl Timestamp {
511    /// Creates a timestamp from microseconds.
512    pub const fn from_us(us: u64) -> Self {
513        Self(us)
514    }
515    /// Returns the timestamp in microseconds.
516    pub fn as_us(self) -> u64 {
517        self.0
518    }
519    /// Returns the duration between two timestamps.
520    pub fn elapsed_since(self, earlier: Timestamp) -> u64 {
521        self.0.saturating_sub(earlier.0)
522    }
523}
524/// An attribute that can be attached to a declaration.
525#[allow(dead_code)]
526#[derive(Clone, Debug, PartialEq, Eq)]
527pub enum DeclAttr {
528    /// Mark as inline (always unfold).
529    Inline,
530    /// Mark as `@[simp]` (add to simp set).
531    Simp,
532    /// Mark as `@[ext]` (register as an extensionality lemma).
533    Ext,
534    /// Mark as reducible.
535    Reducible,
536    /// An unknown attribute with a name.
537    Unknown(String),
538}
539#[allow(dead_code)]
540impl DeclAttr {
541    /// Returns the string name of the attribute.
542    pub fn name(&self) -> &str {
543        match self {
544            DeclAttr::Inline => "inline",
545            DeclAttr::Simp => "simp",
546            DeclAttr::Ext => "ext",
547            DeclAttr::Reducible => "reducible",
548            DeclAttr::Unknown(s) => s.as_str(),
549        }
550    }
551}
552/// Unified constant info enum (mirrors LEAN 4's `constant_info`).
553///
554/// Every declaration in the environment is stored as a `ConstantInfo`.
555/// The type checker dispatches on this enum to determine reduction behavior.
556#[derive(Clone, Debug, PartialEq)]
557pub enum ConstantInfo {
558    /// Axiom declaration.
559    Axiom(AxiomVal),
560    /// Definition with body.
561    Definition(DefinitionVal),
562    /// Theorem with proof.
563    Theorem(TheoremVal),
564    /// Opaque definition.
565    Opaque(OpaqueVal),
566    /// Inductive type.
567    Inductive(InductiveVal),
568    /// Constructor of inductive type.
569    Constructor(ConstructorVal),
570    /// Recursor (eliminator).
571    Recursor(RecursorVal),
572    /// Quotient type component.
573    Quotient(QuotVal),
574}
575impl ConstantInfo {
576    /// Get the name of this constant.
577    pub fn name(&self) -> &Name {
578        &self.common().name
579    }
580    /// Get the type of this constant.
581    pub fn ty(&self) -> &Expr {
582        &self.common().ty
583    }
584    /// Get the universe level parameters.
585    pub fn level_params(&self) -> &[Name] {
586        &self.common().level_params
587    }
588    /// Get the common constant value.
589    pub fn common(&self) -> &ConstantVal {
590        match self {
591            ConstantInfo::Axiom(v) => &v.common,
592            ConstantInfo::Definition(v) => &v.common,
593            ConstantInfo::Theorem(v) => &v.common,
594            ConstantInfo::Opaque(v) => &v.common,
595            ConstantInfo::Inductive(v) => &v.common,
596            ConstantInfo::Constructor(v) => &v.common,
597            ConstantInfo::Recursor(v) => &v.common,
598            ConstantInfo::Quotient(v) => &v.common,
599        }
600    }
601    /// Check if this is an axiom.
602    pub fn is_axiom(&self) -> bool {
603        matches!(self, ConstantInfo::Axiom(_))
604    }
605    /// Check if this is a definition.
606    pub fn is_definition(&self) -> bool {
607        matches!(self, ConstantInfo::Definition(_))
608    }
609    /// Check if this is a theorem.
610    pub fn is_theorem(&self) -> bool {
611        matches!(self, ConstantInfo::Theorem(_))
612    }
613    /// Check if this is opaque.
614    pub fn is_opaque(&self) -> bool {
615        matches!(self, ConstantInfo::Opaque(_))
616    }
617    /// Check if this is an inductive type.
618    pub fn is_inductive(&self) -> bool {
619        matches!(self, ConstantInfo::Inductive(_))
620    }
621    /// Check if this is a constructor.
622    pub fn is_constructor(&self) -> bool {
623        matches!(self, ConstantInfo::Constructor(_))
624    }
625    /// Check if this is a recursor.
626    pub fn is_recursor(&self) -> bool {
627        matches!(self, ConstantInfo::Recursor(_))
628    }
629    /// Check if this is a quotient component.
630    pub fn is_quotient(&self) -> bool {
631        matches!(self, ConstantInfo::Quotient(_))
632    }
633    /// Get the definition value if this is a Definition.
634    pub fn to_definition_val(&self) -> Option<&DefinitionVal> {
635        match self {
636            ConstantInfo::Definition(v) => Some(v),
637            _ => None,
638        }
639    }
640    /// Get the inductive value if this is an Inductive.
641    pub fn to_inductive_val(&self) -> Option<&InductiveVal> {
642        match self {
643            ConstantInfo::Inductive(v) => Some(v),
644            _ => None,
645        }
646    }
647    /// Get the constructor value if this is a Constructor.
648    pub fn to_constructor_val(&self) -> Option<&ConstructorVal> {
649        match self {
650            ConstantInfo::Constructor(v) => Some(v),
651            _ => None,
652        }
653    }
654    /// Get the recursor value if this is a Recursor.
655    pub fn to_recursor_val(&self) -> Option<&RecursorVal> {
656        match self {
657            ConstantInfo::Recursor(v) => Some(v),
658            _ => None,
659        }
660    }
661    /// Get the quotient value if this is a Quotient.
662    pub fn to_quotient_val(&self) -> Option<&QuotVal> {
663        match self {
664            ConstantInfo::Quotient(v) => Some(v),
665            _ => None,
666        }
667    }
668    /// Get the axiom value if this is an Axiom.
669    pub fn to_axiom_val(&self) -> Option<&AxiomVal> {
670        match self {
671            ConstantInfo::Axiom(v) => Some(v),
672            _ => None,
673        }
674    }
675    /// Get the theorem value if this is a Theorem.
676    pub fn to_theorem_val(&self) -> Option<&TheoremVal> {
677        match self {
678            ConstantInfo::Theorem(v) => Some(v),
679            _ => None,
680        }
681    }
682    /// Get the opaque value if this is an Opaque.
683    pub fn to_opaque_val(&self) -> Option<&OpaqueVal> {
684        match self {
685            ConstantInfo::Opaque(v) => Some(v),
686            _ => None,
687        }
688    }
689    /// Check if this constant has a computable value.
690    ///
691    /// `allow_opaque` controls whether opaque definitions are considered.
692    pub fn has_value(&self, allow_opaque: bool) -> bool {
693        match self {
694            ConstantInfo::Definition(_) | ConstantInfo::Theorem(_) => true,
695            ConstantInfo::Opaque(_) => allow_opaque,
696            _ => false,
697        }
698    }
699    /// Get the value (body/proof) if available.
700    pub fn value(&self) -> Option<&Expr> {
701        match self {
702            ConstantInfo::Definition(v) => Some(&v.value),
703            ConstantInfo::Theorem(v) => Some(&v.value),
704            ConstantInfo::Opaque(v) => Some(&v.value),
705            _ => None,
706        }
707    }
708    /// Get the reducibility hint.
709    pub fn reducibility_hint(&self) -> ReducibilityHint {
710        match self {
711            ConstantInfo::Definition(v) => v.hints,
712            ConstantInfo::Theorem(_) | ConstantInfo::Opaque(_) | ConstantInfo::Axiom(_) => {
713                ReducibilityHint::Opaque
714            }
715            _ => ReducibilityHint::Opaque,
716        }
717    }
718    /// Check if this declaration is unsafe.
719    pub fn is_unsafe(&self) -> bool {
720        match self {
721            ConstantInfo::Axiom(v) => v.is_unsafe,
722            ConstantInfo::Definition(v) => v.safety == DefinitionSafety::Unsafe,
723            ConstantInfo::Opaque(v) => v.is_unsafe,
724            ConstantInfo::Inductive(v) => v.is_unsafe,
725            ConstantInfo::Constructor(v) => v.is_unsafe,
726            ConstantInfo::Recursor(v) => v.is_unsafe,
727            ConstantInfo::Theorem(_) | ConstantInfo::Quotient(_) => false,
728        }
729    }
730    /// Check if this is a structure-like inductive (single constructor, not recursive).
731    pub fn is_structure_like(&self) -> bool {
732        match self {
733            ConstantInfo::Inductive(v) => v.ctors.len() == 1 && !v.is_rec && v.num_indices == 0,
734            _ => false,
735        }
736    }
737}
738impl ConstantInfo {
739    /// Return the kind of this constant.
740    pub fn kind(&self) -> ConstantKind {
741        match self {
742            ConstantInfo::Axiom(_) => ConstantKind::Axiom,
743            ConstantInfo::Definition(_) => ConstantKind::Definition,
744            ConstantInfo::Theorem(_) => ConstantKind::Theorem,
745            ConstantInfo::Opaque(_) => ConstantKind::Opaque,
746            ConstantInfo::Inductive(_) => ConstantKind::Inductive,
747            ConstantInfo::Constructor(_) => ConstantKind::Constructor,
748            ConstantInfo::Recursor(_) => ConstantKind::Recursor,
749            ConstantInfo::Quotient(_) => ConstantKind::Quotient,
750        }
751    }
752    /// Build a summary of this constant.
753    pub fn summarize(&self) -> ConstantSummary {
754        ConstantSummary {
755            name: self.name().clone(),
756            kind: self.kind(),
757            num_level_params: self.level_params().len(),
758            is_polymorphic: !self.level_params().is_empty(),
759        }
760    }
761    /// Return the number of universe-level parameters.
762    pub fn num_level_params(&self) -> usize {
763        self.level_params().len()
764    }
765    /// Whether this constant is universe-polymorphic.
766    pub fn is_polymorphic(&self) -> bool {
767        !self.level_params().is_empty()
768    }
769    /// For constructors, return the parent inductive name.
770    pub fn parent_inductive(&self) -> Option<&Name> {
771        match self {
772            ConstantInfo::Constructor(cv) => Some(&cv.induct),
773            _ => None,
774        }
775    }
776    /// For inductives, return the number of parameters.
777    pub fn inductive_num_params(&self) -> Option<usize> {
778        match self {
779            ConstantInfo::Inductive(iv) => Some(iv.num_params as usize),
780            _ => None,
781        }
782    }
783    /// For inductives, return the number of indices.
784    pub fn inductive_num_indices(&self) -> Option<usize> {
785        match self {
786            ConstantInfo::Inductive(iv) => Some(iv.num_indices as usize),
787            _ => None,
788        }
789    }
790    /// For inductives, return the list of constructor names.
791    pub fn inductive_constructors(&self) -> Option<&[Name]> {
792        match self {
793            ConstantInfo::Inductive(iv) => Some(&iv.ctors),
794            _ => None,
795        }
796    }
797    /// For constructors, return the number of fields.
798    pub fn ctor_num_fields(&self) -> Option<usize> {
799        match self {
800            ConstantInfo::Constructor(cv) => Some(cv.num_fields as usize),
801            _ => None,
802        }
803    }
804    /// For recursors, return the recursor rules.
805    pub fn recursor_rules(&self) -> Option<&[RecursorRule]> {
806        match self {
807            ConstantInfo::Recursor(rv) => Some(&rv.rules),
808            _ => None,
809        }
810    }
811    /// Return a display string for this constant.
812    pub fn display_string(&self) -> String {
813        let kind = self.kind().as_str();
814        if self.level_params().is_empty() {
815            format!("{} {}", kind, self.name())
816        } else {
817            let params: Vec<String> = self
818                .level_params()
819                .iter()
820                .map(|p| format!("{}", p))
821                .collect();
822            format!("{} {}.{{{}}} ", kind, self.name(), params.join(", "))
823        }
824    }
825}
826/// Safety classification for definitions.
827#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
828pub enum DefinitionSafety {
829    /// Safe: pure and terminating.
830    Safe,
831    /// Unsafe: may use unsafe declarations.
832    Unsafe,
833    /// Partial: may not terminate.
834    Partial,
835}
836impl DefinitionSafety {
837    /// Whether this safety level is safe (not partial or unsafe).
838    pub fn is_safe(&self) -> bool {
839        matches!(self, DefinitionSafety::Safe)
840    }
841    /// Whether this definition is partial (allows general recursion).
842    pub fn is_partial(&self) -> bool {
843        matches!(self, DefinitionSafety::Partial)
844    }
845    /// Return a human-readable string for the safety level.
846    pub fn as_str(&self) -> &'static str {
847        match self {
848            DefinitionSafety::Safe => "safe",
849            DefinitionSafety::Unsafe => "unsafe",
850            DefinitionSafety::Partial => "partial",
851        }
852    }
853}
854/// A type-safe wrapper around a `u32` identifier.
855#[allow(dead_code)]
856#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
857pub struct TypedId<T> {
858    pub(super) id: u32,
859    _phantom: std::marker::PhantomData<T>,
860}
861#[allow(dead_code)]
862impl<T> TypedId<T> {
863    /// Creates a new typed ID.
864    pub const fn new(id: u32) -> Self {
865        Self {
866            id,
867            _phantom: std::marker::PhantomData,
868        }
869    }
870    /// Returns the raw `u32` ID.
871    pub fn raw(&self) -> u32 {
872        self.id
873    }
874}
875/// The kind of a declaration.
876#[allow(dead_code)]
877#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
878pub enum DeclKind {
879    /// A theorem with a proof body.
880    Theorem,
881    /// A definition with a definitional body.
882    Definition,
883    /// An opaque definition (body not unfolded during type-checking).
884    Opaque,
885    /// An axiom (no body).
886    Axiom,
887    /// A structure (record type).
888    Structure,
889    /// An inductive type.
890    Inductive,
891    /// A recursive definition.
892    Recursive,
893    /// An instance of a typeclass.
894    Instance,
895}
896#[allow(dead_code)]
897impl DeclKind {
898    /// Returns `true` if the declaration has a body.
899    pub fn has_body(self) -> bool {
900        !matches!(self, DeclKind::Axiom)
901    }
902    /// Returns `true` if this is a type-defining declaration.
903    pub fn is_type_decl(self) -> bool {
904        matches!(self, DeclKind::Structure | DeclKind::Inductive)
905    }
906    /// Returns a short string label.
907    pub fn label(self) -> &'static str {
908        match self {
909            DeclKind::Theorem => "theorem",
910            DeclKind::Definition => "def",
911            DeclKind::Opaque => "opaque",
912            DeclKind::Axiom => "axiom",
913            DeclKind::Structure => "structure",
914            DeclKind::Inductive => "inductive",
915            DeclKind::Recursive => "recdef",
916            DeclKind::Instance => "instance",
917        }
918    }
919}
920/// Interns strings to save memory (each unique string stored once).
921#[allow(dead_code)]
922pub struct StringInterner {
923    strings: Vec<String>,
924    map: std::collections::HashMap<String, u32>,
925}
926#[allow(dead_code)]
927impl StringInterner {
928    /// Creates a new string interner.
929    pub fn new() -> Self {
930        Self {
931            strings: Vec::new(),
932            map: std::collections::HashMap::new(),
933        }
934    }
935    /// Interns `s` and returns its ID.
936    pub fn intern(&mut self, s: &str) -> u32 {
937        if let Some(&id) = self.map.get(s) {
938            return id;
939        }
940        let id = self.strings.len() as u32;
941        self.strings.push(s.to_string());
942        self.map.insert(s.to_string(), id);
943        id
944    }
945    /// Returns the string for `id`.
946    pub fn get(&self, id: u32) -> Option<&str> {
947        self.strings.get(id as usize).map(|s| s.as_str())
948    }
949    /// Returns the total number of interned strings.
950    pub fn len(&self) -> usize {
951        self.strings.len()
952    }
953    /// Returns `true` if empty.
954    pub fn is_empty(&self) -> bool {
955        self.strings.is_empty()
956    }
957}
958/// A growable ring buffer with fixed maximum capacity.
959#[allow(dead_code)]
960pub struct RingBuffer<T> {
961    data: Vec<Option<T>>,
962    head: usize,
963    tail: usize,
964    count: usize,
965    capacity: usize,
966}
967#[allow(dead_code)]
968impl<T> RingBuffer<T> {
969    /// Creates a new ring buffer with the given capacity.
970    pub fn new(capacity: usize) -> Self {
971        let mut data = Vec::with_capacity(capacity);
972        for _ in 0..capacity {
973            data.push(None);
974        }
975        Self {
976            data,
977            head: 0,
978            tail: 0,
979            count: 0,
980            capacity,
981        }
982    }
983    /// Pushes a value, overwriting the oldest if full.
984    pub fn push(&mut self, val: T) {
985        if self.count == self.capacity {
986            self.data[self.head] = Some(val);
987            self.head = (self.head + 1) % self.capacity;
988            self.tail = (self.tail + 1) % self.capacity;
989        } else {
990            self.data[self.tail] = Some(val);
991            self.tail = (self.tail + 1) % self.capacity;
992            self.count += 1;
993        }
994    }
995    /// Pops the oldest value.
996    pub fn pop(&mut self) -> Option<T> {
997        if self.count == 0 {
998            return None;
999        }
1000        let val = self.data[self.head].take();
1001        self.head = (self.head + 1) % self.capacity;
1002        self.count -= 1;
1003        val
1004    }
1005    /// Returns the number of elements.
1006    pub fn len(&self) -> usize {
1007        self.count
1008    }
1009    /// Returns `true` if empty.
1010    pub fn is_empty(&self) -> bool {
1011        self.count == 0
1012    }
1013    /// Returns `true` if at capacity.
1014    pub fn is_full(&self) -> bool {
1015        self.count == self.capacity
1016    }
1017}
1018/// Inductive type declaration value.
1019#[derive(Clone, Debug, PartialEq)]
1020pub struct InductiveVal {
1021    /// Common fields.
1022    pub common: ConstantVal,
1023    /// Number of parameters (uniform across constructors).
1024    pub num_params: u32,
1025    /// Number of indices (vary per constructor).
1026    pub num_indices: u32,
1027    /// All inductive types in mutual declaration.
1028    pub all: Vec<Name>,
1029    /// Constructor names.
1030    pub ctors: Vec<Name>,
1031    /// Number of nested inductive uses.
1032    pub num_nested: u32,
1033    /// Whether this type is recursively defined.
1034    pub is_rec: bool,
1035    /// Whether this is unsafe.
1036    pub is_unsafe: bool,
1037    /// Whether this is reflexive (all arguments are params).
1038    pub is_reflexive: bool,
1039    /// Whether this type lives in Prop.
1040    pub is_prop: bool,
1041}
1042/// A sequence number that can be compared for ordering.
1043#[allow(dead_code)]
1044#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1045pub struct SeqNum(u64);
1046#[allow(dead_code)]
1047impl SeqNum {
1048    /// Creates sequence number zero.
1049    pub const ZERO: SeqNum = SeqNum(0);
1050    /// Advances the sequence number by one.
1051    pub fn next(self) -> SeqNum {
1052        SeqNum(self.0 + 1)
1053    }
1054    /// Returns the raw value.
1055    pub fn value(self) -> u64 {
1056        self.0
1057    }
1058}
1059/// A bidirectional map between two types.
1060#[allow(dead_code)]
1061pub struct BiMap<A: std::hash::Hash + Eq + Clone, B: std::hash::Hash + Eq + Clone> {
1062    forward: std::collections::HashMap<A, B>,
1063    backward: std::collections::HashMap<B, A>,
1064}
1065#[allow(dead_code)]
1066impl<A: std::hash::Hash + Eq + Clone, B: std::hash::Hash + Eq + Clone> BiMap<A, B> {
1067    /// Creates an empty bidirectional map.
1068    pub fn new() -> Self {
1069        Self {
1070            forward: std::collections::HashMap::new(),
1071            backward: std::collections::HashMap::new(),
1072        }
1073    }
1074    /// Inserts a pair `(a, b)`.
1075    pub fn insert(&mut self, a: A, b: B) {
1076        self.forward.insert(a.clone(), b.clone());
1077        self.backward.insert(b, a);
1078    }
1079    /// Looks up `b` for a given `a`.
1080    pub fn get_b(&self, a: &A) -> Option<&B> {
1081        self.forward.get(a)
1082    }
1083    /// Looks up `a` for a given `b`.
1084    pub fn get_a(&self, b: &B) -> Option<&A> {
1085        self.backward.get(b)
1086    }
1087    /// Returns the number of pairs.
1088    pub fn len(&self) -> usize {
1089        self.forward.len()
1090    }
1091    /// Returns `true` if empty.
1092    pub fn is_empty(&self) -> bool {
1093        self.forward.is_empty()
1094    }
1095}
1096/// Opaque declaration value.
1097#[derive(Clone, Debug, PartialEq)]
1098pub struct OpaqueVal {
1099    /// Common fields.
1100    pub common: ConstantVal,
1101    /// Hidden body.
1102    pub value: Expr,
1103    /// Whether this is unsafe.
1104    pub is_unsafe: bool,
1105    /// Names in mutual declaration group.
1106    pub all: Vec<Name>,
1107}
1108/// Visibility of a declaration.
1109#[allow(dead_code)]
1110#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1111pub enum DeclVisibility {
1112    /// Visible everywhere.
1113    Public,
1114    /// Visible only within the current namespace.
1115    Protected,
1116    /// Visible only within the current file.
1117    Private,
1118}
1119#[allow(dead_code)]
1120impl DeclVisibility {
1121    /// Returns `true` if the declaration is visible from outside its module.
1122    pub fn is_externally_visible(self) -> bool {
1123        matches!(self, DeclVisibility::Public)
1124    }
1125}
1126/// A counter that dispenses monotonically increasing `TypedId` values.
1127#[allow(dead_code)]
1128pub struct IdDispenser<T> {
1129    next: u32,
1130    _phantom: std::marker::PhantomData<T>,
1131}
1132#[allow(dead_code)]
1133impl<T> IdDispenser<T> {
1134    /// Creates a new dispenser starting from zero.
1135    pub fn new() -> Self {
1136        Self {
1137            next: 0,
1138            _phantom: std::marker::PhantomData,
1139        }
1140    }
1141    /// Dispenses the next ID.
1142    #[allow(clippy::should_implement_trait)]
1143    pub fn next(&mut self) -> TypedId<T> {
1144        let id = TypedId::new(self.next);
1145        self.next += 1;
1146        id
1147    }
1148    /// Returns the number of IDs dispensed.
1149    pub fn count(&self) -> u32 {
1150        self.next
1151    }
1152}
1153/// Tracks the dependency graph between declarations.
1154#[allow(dead_code)]
1155pub struct DeclDependencies {
1156    /// `deps[i]` is the set of declaration indices that `i` depends on.
1157    deps: Vec<std::collections::HashSet<usize>>,
1158}
1159#[allow(dead_code)]
1160impl DeclDependencies {
1161    /// Creates a dependency table for `n` declarations.
1162    pub fn new(n: usize) -> Self {
1163        Self {
1164            deps: vec![std::collections::HashSet::new(); n],
1165        }
1166    }
1167    /// Adds a dependency: `dependent` depends on `dependency`.
1168    pub fn add(&mut self, dependent: usize, dependency: usize) {
1169        if dependent < self.deps.len() {
1170            self.deps[dependent].insert(dependency);
1171        }
1172    }
1173    /// Returns the dependencies of `idx`.
1174    pub fn deps_of(&self, idx: usize) -> &std::collections::HashSet<usize> {
1175        static EMPTY: std::sync::OnceLock<std::collections::HashSet<usize>> =
1176            std::sync::OnceLock::new();
1177        self.deps
1178            .get(idx)
1179            .unwrap_or_else(|| EMPTY.get_or_init(std::collections::HashSet::new))
1180    }
1181    /// Returns `true` if `dependent` directly depends on `dependency`.
1182    pub fn directly_depends(&self, dependent: usize, dependency: usize) -> bool {
1183        self.deps_of(dependent).contains(&dependency)
1184    }
1185    /// Returns the total number of dependency edges.
1186    pub fn total_edges(&self) -> usize {
1187        self.deps.iter().map(|s| s.len()).sum()
1188    }
1189}
1190/// A set of non-overlapping integer intervals.
1191#[allow(dead_code)]
1192pub struct IntervalSet {
1193    intervals: Vec<(i64, i64)>,
1194}
1195#[allow(dead_code)]
1196impl IntervalSet {
1197    /// Creates an empty interval set.
1198    pub fn new() -> Self {
1199        Self {
1200            intervals: Vec::new(),
1201        }
1202    }
1203    /// Adds the interval `[lo, hi]` to the set.
1204    pub fn add(&mut self, lo: i64, hi: i64) {
1205        if lo > hi {
1206            return;
1207        }
1208        let mut new_lo = lo;
1209        let mut new_hi = hi;
1210        let mut i = 0;
1211        while i < self.intervals.len() {
1212            let (il, ih) = self.intervals[i];
1213            if ih < new_lo - 1 {
1214                i += 1;
1215                continue;
1216            }
1217            if il > new_hi + 1 {
1218                break;
1219            }
1220            new_lo = new_lo.min(il);
1221            new_hi = new_hi.max(ih);
1222            self.intervals.remove(i);
1223        }
1224        self.intervals.insert(i, (new_lo, new_hi));
1225    }
1226    /// Returns `true` if `x` is in the set.
1227    pub fn contains(&self, x: i64) -> bool {
1228        self.intervals.iter().any(|&(lo, hi)| x >= lo && x <= hi)
1229    }
1230    /// Returns the number of intervals.
1231    pub fn num_intervals(&self) -> usize {
1232        self.intervals.len()
1233    }
1234    /// Returns the total count of integers covered.
1235    pub fn cardinality(&self) -> i64 {
1236        self.intervals.iter().map(|&(lo, hi)| hi - lo + 1).sum()
1237    }
1238}
1239/// A generation counter for validity tracking.
1240#[allow(dead_code)]
1241#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1242pub struct Generation(u32);
1243#[allow(dead_code)]
1244impl Generation {
1245    /// The initial generation.
1246    pub const INITIAL: Generation = Generation(0);
1247    /// Advances to the next generation.
1248    pub fn advance(self) -> Generation {
1249        Generation(self.0 + 1)
1250    }
1251    /// Returns the raw generation number.
1252    pub fn number(self) -> u32 {
1253        self.0
1254    }
1255}
1256/// A FIFO work queue.
1257#[allow(dead_code)]
1258pub struct WorkQueue<T> {
1259    items: std::collections::VecDeque<T>,
1260}
1261#[allow(dead_code)]
1262impl<T> WorkQueue<T> {
1263    /// Creates a new empty queue.
1264    pub fn new() -> Self {
1265        Self {
1266            items: std::collections::VecDeque::new(),
1267        }
1268    }
1269    /// Enqueues a work item.
1270    pub fn enqueue(&mut self, item: T) {
1271        self.items.push_back(item);
1272    }
1273    /// Dequeues the next work item.
1274    pub fn dequeue(&mut self) -> Option<T> {
1275        self.items.pop_front()
1276    }
1277    /// Returns `true` if empty.
1278    pub fn is_empty(&self) -> bool {
1279        self.items.is_empty()
1280    }
1281    /// Returns the number of pending items.
1282    pub fn len(&self) -> usize {
1283        self.items.len()
1284    }
1285}
1286/// Definition declaration value.
1287#[derive(Clone, Debug, PartialEq)]
1288pub struct DefinitionVal {
1289    /// Common fields.
1290    pub common: ConstantVal,
1291    /// Definition body.
1292    pub value: Expr,
1293    /// Reducibility hints for unfolding strategy.
1294    pub hints: ReducibilityHint,
1295    /// Safety classification.
1296    pub safety: DefinitionSafety,
1297    /// Names in mutual definition group.
1298    pub all: Vec<Name>,
1299}
1300/// Quotient declaration value.
1301#[derive(Clone, Debug, PartialEq)]
1302pub struct QuotVal {
1303    /// Common fields.
1304    pub common: ConstantVal,
1305    /// Which quotient component.
1306    pub kind: QuotKind,
1307}
1308/// A summary of a declaration's key properties.
1309#[derive(Debug, Clone)]
1310pub struct ConstantSummary {
1311    /// The name of the constant.
1312    pub name: Name,
1313    /// The kind of constant.
1314    pub kind: ConstantKind,
1315    /// Number of universe level parameters.
1316    pub num_level_params: usize,
1317    /// Whether this is universe-polymorphic.
1318    pub is_polymorphic: bool,
1319}
1320/// Tracks the frequency of items.
1321#[allow(dead_code)]
1322pub struct FrequencyTable<T: std::hash::Hash + Eq + Clone> {
1323    counts: std::collections::HashMap<T, u64>,
1324}
1325#[allow(dead_code)]
1326impl<T: std::hash::Hash + Eq + Clone> FrequencyTable<T> {
1327    /// Creates a new empty frequency table.
1328    pub fn new() -> Self {
1329        Self {
1330            counts: std::collections::HashMap::new(),
1331        }
1332    }
1333    /// Records one occurrence of `item`.
1334    pub fn record(&mut self, item: T) {
1335        *self.counts.entry(item).or_insert(0) += 1;
1336    }
1337    /// Returns the frequency of `item`.
1338    pub fn freq(&self, item: &T) -> u64 {
1339        self.counts.get(item).copied().unwrap_or(0)
1340    }
1341    /// Returns the item with the highest frequency.
1342    pub fn most_frequent(&self) -> Option<(&T, u64)> {
1343        self.counts
1344            .iter()
1345            .max_by_key(|(_, &v)| v)
1346            .map(|(k, &v)| (k, v))
1347    }
1348    /// Returns the total number of recordings.
1349    pub fn total(&self) -> u64 {
1350        self.counts.values().sum()
1351    }
1352    /// Returns the number of distinct items.
1353    pub fn distinct(&self) -> usize {
1354        self.counts.len()
1355    }
1356}
1357/// The kind of constant declaration.
1358#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1359pub enum ConstantKind {
1360    /// An axiom declaration.
1361    Axiom,
1362    /// A definition declaration.
1363    Definition,
1364    /// A theorem declaration.
1365    Theorem,
1366    /// An opaque definition.
1367    Opaque,
1368    /// An inductive type declaration.
1369    Inductive,
1370    /// A constructor of an inductive type.
1371    Constructor,
1372    /// A recursor (eliminator) for an inductive type.
1373    Recursor,
1374    /// A quotient type declaration.
1375    Quotient,
1376}
1377impl ConstantKind {
1378    /// Return a human-readable name for the kind.
1379    pub fn as_str(&self) -> &'static str {
1380        match self {
1381            ConstantKind::Axiom => "axiom",
1382            ConstantKind::Definition => "definition",
1383            ConstantKind::Theorem => "theorem",
1384            ConstantKind::Opaque => "opaque",
1385            ConstantKind::Inductive => "inductive",
1386            ConstantKind::Constructor => "constructor",
1387            ConstantKind::Recursor => "recursor",
1388            ConstantKind::Quotient => "quotient",
1389        }
1390    }
1391    /// Whether this kind can have a proof term (body).
1392    pub fn has_body(&self) -> bool {
1393        matches!(
1394            self,
1395            ConstantKind::Definition | ConstantKind::Theorem | ConstantKind::Opaque
1396        )
1397    }
1398    /// Whether this kind is a structural element of an inductive type.
1399    pub fn is_inductive_family(&self) -> bool {
1400        matches!(
1401            self,
1402            ConstantKind::Inductive | ConstantKind::Constructor | ConstantKind::Recursor
1403        )
1404    }
1405}
1406/// Filters declarations by kind, namespace, or attributes.
1407#[allow(dead_code)]
1408pub struct DeclFilter {
1409    allowed_kinds: Option<Vec<DeclKind>>,
1410    ns_prefix: Option<String>,
1411    required_attrs: Vec<DeclAttr>,
1412}
1413#[allow(dead_code)]
1414impl DeclFilter {
1415    /// Creates a filter that accepts everything.
1416    pub fn accept_all() -> Self {
1417        Self {
1418            allowed_kinds: None,
1419            ns_prefix: None,
1420            required_attrs: Vec::new(),
1421        }
1422    }
1423    /// Restricts to specific kinds.
1424    pub fn with_kinds(mut self, kinds: Vec<DeclKind>) -> Self {
1425        self.allowed_kinds = Some(kinds);
1426        self
1427    }
1428    /// Restricts to declarations in the given namespace prefix.
1429    pub fn in_namespace(mut self, prefix: impl Into<String>) -> Self {
1430        self.ns_prefix = Some(prefix.into());
1431        self
1432    }
1433    /// Requires a specific attribute.
1434    pub fn with_attr(mut self, attr: DeclAttr) -> Self {
1435        self.required_attrs.push(attr);
1436        self
1437    }
1438    /// Tests whether a signature passes the filter.
1439    pub fn accepts(&self, sig: &DeclSignature, kind: DeclKind, attrs: &[DeclAttr]) -> bool {
1440        if let Some(ref kinds) = self.allowed_kinds {
1441            if !kinds.contains(&kind) {
1442                return false;
1443            }
1444        }
1445        if let Some(ref prefix) = self.ns_prefix {
1446            if !sig.name.starts_with(prefix.as_str()) {
1447                return false;
1448            }
1449        }
1450        for req in &self.required_attrs {
1451            if !attrs.contains(req) {
1452                return false;
1453            }
1454        }
1455        true
1456    }
1457}
1458/// A simple LRU cache backed by a linked list + hash map.
1459#[allow(dead_code)]
1460pub struct SimpleLruCache<K: std::hash::Hash + Eq + Clone, V: Clone> {
1461    capacity: usize,
1462    map: std::collections::HashMap<K, usize>,
1463    keys: Vec<K>,
1464    vals: Vec<V>,
1465    order: Vec<usize>,
1466}
1467#[allow(dead_code)]
1468impl<K: std::hash::Hash + Eq + Clone, V: Clone> SimpleLruCache<K, V> {
1469    /// Creates a new LRU cache with the given capacity.
1470    pub fn new(capacity: usize) -> Self {
1471        assert!(capacity > 0);
1472        Self {
1473            capacity,
1474            map: std::collections::HashMap::new(),
1475            keys: Vec::new(),
1476            vals: Vec::new(),
1477            order: Vec::new(),
1478        }
1479    }
1480    /// Inserts or updates a key-value pair.
1481    pub fn put(&mut self, key: K, val: V) {
1482        if let Some(&idx) = self.map.get(&key) {
1483            self.vals[idx] = val;
1484            self.order.retain(|&x| x != idx);
1485            self.order.insert(0, idx);
1486            return;
1487        }
1488        if self.keys.len() >= self.capacity {
1489            let evict_idx = *self
1490                .order
1491                .last()
1492                .expect("order list must be non-empty before eviction");
1493            self.map.remove(&self.keys[evict_idx]);
1494            self.order.pop();
1495            self.keys[evict_idx] = key.clone();
1496            self.vals[evict_idx] = val;
1497            self.map.insert(key, evict_idx);
1498            self.order.insert(0, evict_idx);
1499        } else {
1500            let idx = self.keys.len();
1501            self.keys.push(key.clone());
1502            self.vals.push(val);
1503            self.map.insert(key, idx);
1504            self.order.insert(0, idx);
1505        }
1506    }
1507    /// Returns a reference to the value for `key`, promoting it.
1508    pub fn get(&mut self, key: &K) -> Option<&V> {
1509        let idx = *self.map.get(key)?;
1510        self.order.retain(|&x| x != idx);
1511        self.order.insert(0, idx);
1512        Some(&self.vals[idx])
1513    }
1514    /// Returns the number of entries.
1515    pub fn len(&self) -> usize {
1516        self.keys.len()
1517    }
1518    /// Returns `true` if empty.
1519    pub fn is_empty(&self) -> bool {
1520        self.keys.is_empty()
1521    }
1522}
1523/// The type signature of a declaration (name + type, no body).
1524#[allow(dead_code)]
1525#[allow(missing_docs)]
1526pub struct DeclSignature {
1527    /// The fully-qualified name.
1528    pub name: String,
1529    /// String representation of the type.
1530    pub ty: String,
1531    /// Universe parameters.
1532    pub uparams: Vec<String>,
1533}
1534#[allow(dead_code)]
1535impl DeclSignature {
1536    /// Creates a new declaration signature.
1537    pub fn new(name: impl Into<String>, ty: impl Into<String>) -> Self {
1538        Self {
1539            name: name.into(),
1540            ty: ty.into(),
1541            uparams: Vec::new(),
1542        }
1543    }
1544    /// Adds a universe parameter.
1545    pub fn with_uparam(mut self, u: impl Into<String>) -> Self {
1546        self.uparams.push(u.into());
1547        self
1548    }
1549    /// Returns `true` if this is a universe-polymorphic signature.
1550    pub fn is_universe_poly(&self) -> bool {
1551        !self.uparams.is_empty()
1552    }
1553}
1554/// A key-value store for diagnostic metadata.
1555#[allow(dead_code)]
1556pub struct DiagMeta {
1557    pub(super) entries: Vec<(String, String)>,
1558}
1559#[allow(dead_code)]
1560impl DiagMeta {
1561    /// Creates an empty metadata store.
1562    pub fn new() -> Self {
1563        Self {
1564            entries: Vec::new(),
1565        }
1566    }
1567    /// Adds a key-value pair.
1568    pub fn add(&mut self, key: impl Into<String>, val: impl Into<String>) {
1569        self.entries.push((key.into(), val.into()));
1570    }
1571    /// Returns the value for `key`, or `None`.
1572    pub fn get(&self, key: &str) -> Option<&str> {
1573        self.entries
1574            .iter()
1575            .find(|(k, _)| k == key)
1576            .map(|(_, v)| v.as_str())
1577    }
1578    /// Returns the number of entries.
1579    pub fn len(&self) -> usize {
1580        self.entries.len()
1581    }
1582    /// Returns `true` if empty.
1583    pub fn is_empty(&self) -> bool {
1584        self.entries.is_empty()
1585    }
1586}