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