Skip to main content

oxilean_kernel/env/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use crate::declaration::{ConstantInfo, ConstantVal, DefinitionSafety, DefinitionVal};
6use crate::reduce::ReducibilityHint;
7use crate::{Expr, Level, Name};
8use std::collections::HashMap;
9
10/// Represents a rewrite rule `lhs → rhs`.
11#[allow(dead_code)]
12#[allow(missing_docs)]
13pub struct RewriteRule {
14    /// The name of the rule.
15    pub name: String,
16    /// A string representation of the LHS pattern.
17    pub lhs: String,
18    /// A string representation of the RHS.
19    pub rhs: String,
20    /// Whether this is a conditional rule (has side conditions).
21    pub conditional: bool,
22}
23#[allow(dead_code)]
24impl RewriteRule {
25    /// Creates an unconditional rewrite rule.
26    pub fn unconditional(
27        name: impl Into<String>,
28        lhs: impl Into<String>,
29        rhs: impl Into<String>,
30    ) -> Self {
31        Self {
32            name: name.into(),
33            lhs: lhs.into(),
34            rhs: rhs.into(),
35            conditional: false,
36        }
37    }
38    /// Creates a conditional rewrite rule.
39    pub fn conditional(
40        name: impl Into<String>,
41        lhs: impl Into<String>,
42        rhs: impl Into<String>,
43    ) -> Self {
44        Self {
45            name: name.into(),
46            lhs: lhs.into(),
47            rhs: rhs.into(),
48            conditional: true,
49        }
50    }
51    /// Returns a textual representation.
52    pub fn display(&self) -> String {
53        format!("{}: {} → {}", self.name, self.lhs, self.rhs)
54    }
55}
56/// A set of rewrite rules.
57#[allow(dead_code)]
58pub struct RewriteRuleSet {
59    rules: Vec<RewriteRule>,
60}
61#[allow(dead_code)]
62impl RewriteRuleSet {
63    /// Creates an empty rule set.
64    pub fn new() -> Self {
65        Self { rules: Vec::new() }
66    }
67    /// Adds a rule.
68    pub fn add(&mut self, rule: RewriteRule) {
69        self.rules.push(rule);
70    }
71    /// Returns the number of rules.
72    pub fn len(&self) -> usize {
73        self.rules.len()
74    }
75    /// Returns `true` if the set is empty.
76    pub fn is_empty(&self) -> bool {
77        self.rules.is_empty()
78    }
79    /// Returns all conditional rules.
80    pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
81        self.rules.iter().filter(|r| r.conditional).collect()
82    }
83    /// Returns all unconditional rules.
84    pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
85        self.rules.iter().filter(|r| !r.conditional).collect()
86    }
87    /// Looks up a rule by name.
88    pub fn get(&self, name: &str) -> Option<&RewriteRule> {
89        self.rules.iter().find(|r| r.name == name)
90    }
91}
92/// A versioned record that stores a history of values.
93#[allow(dead_code)]
94pub struct VersionedRecord<T: Clone> {
95    /// Every earlier value, oldest first: version `n` is `earlier[n]`.
96    earlier: Vec<T>,
97    /// The latest value (version `earlier.len()`), declared last so it drops last.
98    current: T,
99}
100#[allow(dead_code)]
101impl<T: Clone> VersionedRecord<T> {
102    /// Creates a new record with an initial value.
103    pub fn new(initial: T) -> Self {
104        Self {
105            earlier: Vec::new(),
106            current: initial,
107        }
108    }
109    /// Updates the record with a new version.
110    pub fn update(&mut self, val: T) {
111        let previous = std::mem::replace(&mut self.current, val);
112        self.earlier.push(previous);
113    }
114    /// Returns the current (latest) value.
115    pub fn current(&self) -> &T {
116        &self.current
117    }
118    /// Returns the value at version `n` (0-indexed), or `None`.
119    pub fn at_version(&self, n: usize) -> Option<&T> {
120        match self.earlier.get(n) {
121            Some(value) => Some(value),
122            None if n == self.earlier.len() => Some(&self.current),
123            None => None,
124        }
125    }
126    /// Returns the version number of the current value.
127    pub fn version(&self) -> usize {
128        self.earlier.len()
129    }
130    /// Returns `true` if more than one version exists.
131    pub fn has_history(&self) -> bool {
132        !self.earlier.is_empty()
133    }
134}
135/// A mutable reference stack for tracking the current "focus" in a tree traversal.
136#[allow(dead_code)]
137pub struct FocusStack<T> {
138    items: Vec<T>,
139}
140#[allow(dead_code)]
141impl<T> FocusStack<T> {
142    /// Creates an empty focus stack.
143    pub fn new() -> Self {
144        Self { items: Vec::new() }
145    }
146    /// Focuses on `item`.
147    pub fn focus(&mut self, item: T) {
148        self.items.push(item);
149    }
150    /// Blurs (pops) the current focus.
151    pub fn blur(&mut self) -> Option<T> {
152        self.items.pop()
153    }
154    /// Returns the current focus, or `None`.
155    pub fn current(&self) -> Option<&T> {
156        self.items.last()
157    }
158    /// Returns the focus depth.
159    pub fn depth(&self) -> usize {
160        self.items.len()
161    }
162    /// Returns `true` if there is no current focus.
163    pub fn is_empty(&self) -> bool {
164        self.items.is_empty()
165    }
166}
167/// A sparse vector: stores only non-default elements.
168#[allow(dead_code)]
169pub struct SparseVec<T: Default + Clone + PartialEq> {
170    entries: std::collections::HashMap<usize, T>,
171    default_: T,
172    logical_len: usize,
173}
174#[allow(dead_code)]
175impl<T: Default + Clone + PartialEq> SparseVec<T> {
176    /// Creates a new sparse vector with logical length `len`.
177    pub fn new(len: usize) -> Self {
178        Self {
179            entries: std::collections::HashMap::new(),
180            default_: T::default(),
181            logical_len: len,
182        }
183    }
184    /// Sets element at `idx`.
185    pub fn set(&mut self, idx: usize, val: T) {
186        if val == self.default_ {
187            self.entries.remove(&idx);
188        } else {
189            self.entries.insert(idx, val);
190        }
191    }
192    /// Gets element at `idx`.
193    pub fn get(&self, idx: usize) -> &T {
194        self.entries.get(&idx).unwrap_or(&self.default_)
195    }
196    /// Returns the logical length.
197    pub fn len(&self) -> usize {
198        self.logical_len
199    }
200    /// Returns whether the collection is empty.
201    pub fn is_empty(&self) -> bool {
202        self.len() == 0
203    }
204    /// Returns the number of non-default elements.
205    pub fn nnz(&self) -> usize {
206        self.entries.len()
207    }
208}
209/// A window iterator that yields overlapping windows of size `n`.
210#[allow(dead_code)]
211pub struct WindowIterator<'a, T> {
212    pub(super) data: &'a [T],
213    pub(super) pos: usize,
214    pub(super) window: usize,
215}
216#[allow(dead_code)]
217impl<'a, T> WindowIterator<'a, T> {
218    /// Creates a new window iterator.
219    pub fn new(data: &'a [T], window: usize) -> Self {
220        Self {
221            data,
222            pos: 0,
223            window,
224        }
225    }
226}
227/// The global environment containing all checked declarations.
228#[derive(Clone, Debug, Default)]
229pub struct Environment {
230    /// All declarations indexed by name (legacy format).
231    declarations: HashMap<Name, Declaration>,
232    /// All constants indexed by name (new LEAN 4-style format).
233    constants: HashMap<Name, ConstantInfo>,
234    /// Whether the four `#QUOT` primitives have been installed via
235    /// [`Environment::add_quot`]. Quotient constants may only be added through
236    /// that once-only entry point (mirroring Lean's `environment::quot_initialized`).
237    quot_initialized: bool,
238}
239impl Environment {
240    /// Create a new empty environment.
241    pub fn new() -> Self {
242        Self {
243            declarations: HashMap::new(),
244            constants: HashMap::new(),
245            quot_initialized: false,
246        }
247    }
248    /// Add a legacy declaration to the environment.
249    ///
250    /// Returns an error if a declaration with the same name already exists.
251    pub fn add(&mut self, decl: Declaration) -> Result<(), EnvError> {
252        let name = decl.name().clone();
253        if self.declarations.contains_key(&name) || self.constants.contains_key(&name) {
254            return Err(EnvError::DuplicateDeclaration(name));
255        }
256        let ci = decl.to_constant_info();
257        self.constants.insert(name.clone(), ci);
258        self.declarations.insert(name, decl);
259        Ok(())
260    }
261    /// Add a ConstantInfo to the environment.
262    ///
263    /// Quotient constants (`ConstantInfo::Quotient`) are rejected here: the four
264    /// `#QUOT` primitives may only be installed atomically through
265    /// [`Environment::add_quot`], which constructs their canonical types
266    /// in-kernel. This prevents a caller from smuggling a `Quotient` entry with
267    /// an arbitrary (possibly unsound) type past the checker.
268    pub fn add_constant(&mut self, ci: ConstantInfo) -> Result<(), EnvError> {
269        if ci.is_quotient() {
270            return Err(EnvError::InvalidQuotient(
271                "quotient constants may only be added via Environment::add_quot".to_string(),
272            ));
273        }
274        let name = ci.name().clone();
275        if self.declarations.contains_key(&name) || self.constants.contains_key(&name) {
276            return Err(EnvError::DuplicateDeclaration(name));
277        }
278        self.constants.insert(name, ci);
279        Ok(())
280    }
281    /// Whether the four `#QUOT` primitives have been installed.
282    pub fn quot_initialized(&self) -> bool {
283        self.quot_initialized
284    }
285    /// Insert a pre-validated quotient constant.
286    ///
287    /// This bypasses the `add_constant` quotient guard and is used *only* by
288    /// [`Environment::add_quot`], which owns the canonical types and enforces
289    /// the once-only / atomicity invariants. It must never be exposed publicly.
290    pub(crate) fn insert_quotient(&mut self, ci: ConstantInfo) {
291        debug_assert!(ci.is_quotient());
292        let name = ci.name().clone();
293        self.constants.insert(name, ci);
294    }
295    /// Mark the quotient primitives as installed (used only by `add_quot`).
296    pub(crate) fn set_quot_initialized(&mut self) {
297        self.quot_initialized = true;
298    }
299    /// Look up a legacy declaration by name.
300    pub fn get(&self, name: &Name) -> Option<&Declaration> {
301        self.declarations.get(name)
302    }
303    /// Look up a constant info by name.
304    pub fn find(&self, name: &Name) -> Option<&ConstantInfo> {
305        self.constants.get(name)
306    }
307    /// Check if a declaration exists.
308    pub fn contains(&self, name: &Name) -> bool {
309        self.declarations.contains_key(name) || self.constants.contains_key(name)
310    }
311    /// Get the number of declarations.
312    pub fn len(&self) -> usize {
313        self.constants.len().max(self.declarations.len())
314    }
315    /// Check if the environment is empty.
316    pub fn is_empty(&self) -> bool {
317        self.declarations.is_empty() && self.constants.is_empty()
318    }
319    /// Get a definition's value and hint (for reduction).
320    pub fn get_defn(&self, name: &Name) -> Option<(Expr, ReducibilityHint)> {
321        if let Some(ci) = self.constants.get(name) {
322            if let Some(val) = ci.value() {
323                return Some((val.clone(), ci.reducibility_hint()));
324            }
325        }
326        self.declarations.get(name).and_then(|decl| {
327            decl.value()
328                .map(|val| (val.clone(), decl.reducibility_hint()))
329        })
330    }
331    /// Check if a name refers to an inductive type.
332    pub fn is_inductive(&self, name: &Name) -> bool {
333        self.constants.get(name).is_some_and(|ci| ci.is_inductive())
334    }
335    /// Check if a name refers to a constructor.
336    pub fn is_constructor(&self, name: &Name) -> bool {
337        self.constants
338            .get(name)
339            .is_some_and(|ci| ci.is_constructor())
340    }
341    /// Check if a name refers to a recursor.
342    pub fn is_recursor(&self, name: &Name) -> bool {
343        self.constants.get(name).is_some_and(|ci| ci.is_recursor())
344    }
345    /// Check if a name refers to a quotient.
346    pub fn is_quotient(&self, name: &Name) -> bool {
347        self.constants.get(name).is_some_and(|ci| ci.is_quotient())
348    }
349    /// Check if a name refers to a structure-like inductive.
350    pub fn is_structure_like(&self, name: &Name) -> bool {
351        self.constants
352            .get(name)
353            .is_some_and(|ci| ci.is_structure_like())
354    }
355    /// Get the inductive type info for a name.
356    pub fn get_inductive_val(&self, name: &Name) -> Option<&crate::declaration::InductiveVal> {
357        self.constants
358            .get(name)
359            .and_then(|ci| ci.to_inductive_val())
360    }
361    /// Get the constructor info for a name.
362    pub fn get_constructor_val(&self, name: &Name) -> Option<&crate::declaration::ConstructorVal> {
363        self.constants
364            .get(name)
365            .and_then(|ci| ci.to_constructor_val())
366    }
367    /// Get the recursor info for a name.
368    pub fn get_recursor_val(&self, name: &Name) -> Option<&crate::declaration::RecursorVal> {
369        self.constants.get(name).and_then(|ci| ci.to_recursor_val())
370    }
371    /// Get the quotient info for a name.
372    pub fn get_quotient_val(&self, name: &Name) -> Option<&crate::declaration::QuotVal> {
373        self.constants.get(name).and_then(|ci| ci.to_quotient_val())
374    }
375    /// Get the type of a constant (from ConstantInfo).
376    pub fn get_type(&self, name: &Name) -> Option<&Expr> {
377        self.constants.get(name).map(|ci| ci.ty())
378    }
379    /// Get the universe level parameters for a constant.
380    pub fn get_level_params(&self, name: &Name) -> Option<&[Name]> {
381        self.constants.get(name).map(|ci| ci.level_params())
382    }
383    /// Instantiate a constant's type with universe levels.
384    pub fn instantiate_const_type(&self, name: &Name, levels: &[Level]) -> Option<Expr> {
385        let ci = self.constants.get(name)?;
386        let params = ci.level_params();
387        if params.is_empty() || levels.is_empty() {
388            return Some(ci.ty().clone());
389        }
390        Some(crate::declaration::instantiate_level_params(
391            ci.ty(),
392            params,
393            levels,
394        ))
395    }
396    /// Iterate over all constant names.
397    pub fn constant_names(&self) -> impl Iterator<Item = &Name> {
398        self.constants.keys()
399    }
400    /// Iterate over all constant infos.
401    pub fn constant_infos(&self) -> impl Iterator<Item = (&Name, &ConstantInfo)> {
402        self.constants.iter()
403    }
404}
405/// Counts of declaration kinds in an environment.
406#[allow(dead_code)]
407#[derive(Debug, Clone, Default)]
408pub struct EnvKindCounts {
409    /// Number of axioms.
410    pub axioms: usize,
411    /// Number of inductive type definitions.
412    pub inductives: usize,
413    /// Number of constructors.
414    pub constructors: usize,
415    /// Number of recursors.
416    pub recursors: usize,
417    /// Number of definitions.
418    pub definitions: usize,
419    /// Number of theorems.
420    pub theorems: usize,
421    /// Other (quotients, etc.).
422    pub other: usize,
423}
424impl EnvKindCounts {
425    /// Total number of declarations.
426    #[allow(dead_code)]
427    pub fn total(&self) -> usize {
428        self.axioms
429            + self.inductives
430            + self.constructors
431            + self.recursors
432            + self.definitions
433            + self.theorems
434            + self.other
435    }
436}
437/// A declaration in the global environment (legacy format).
438#[derive(Clone, Debug)]
439pub enum Declaration {
440    /// Axiom: postulated type without proof
441    Axiom {
442        /// Name of the axiom
443        name: Name,
444        /// Universe parameters
445        univ_params: Vec<Name>,
446        /// Type of the axiom
447        ty: Expr,
448    },
449    /// Definition: has a computational value
450    Definition {
451        /// Name of the definition
452        name: Name,
453        /// Universe parameters
454        univ_params: Vec<Name>,
455        /// Type of the definition
456        ty: Expr,
457        /// Value/body of the definition
458        val: Expr,
459        /// Reducibility hint
460        hint: ReducibilityHint,
461    },
462    /// Theorem: like definition but value is a proof (typically opaque)
463    Theorem {
464        /// Name of the theorem
465        name: Name,
466        /// Universe parameters
467        univ_params: Vec<Name>,
468        /// Type of the theorem (the proposition)
469        ty: Expr,
470        /// Proof of the theorem
471        val: Expr,
472    },
473    /// Opaque: definition that should never be unfolded
474    Opaque {
475        /// Name of the opaque definition
476        name: Name,
477        /// Universe parameters
478        univ_params: Vec<Name>,
479        /// Type of the definition
480        ty: Expr,
481        /// Value of the definition (hidden)
482        val: Expr,
483    },
484}
485impl Declaration {
486    /// Get the name of this declaration.
487    pub fn name(&self) -> &Name {
488        match self {
489            Declaration::Axiom { name, .. }
490            | Declaration::Definition { name, .. }
491            | Declaration::Theorem { name, .. }
492            | Declaration::Opaque { name, .. } => name,
493        }
494    }
495    /// Get the type of this declaration.
496    pub fn ty(&self) -> &Expr {
497        match self {
498            Declaration::Axiom { ty, .. }
499            | Declaration::Definition { ty, .. }
500            | Declaration::Theorem { ty, .. }
501            | Declaration::Opaque { ty, .. } => ty,
502        }
503    }
504    /// Get the universe parameters.
505    pub fn univ_params(&self) -> &[Name] {
506        match self {
507            Declaration::Axiom { univ_params, .. }
508            | Declaration::Definition { univ_params, .. }
509            | Declaration::Theorem { univ_params, .. }
510            | Declaration::Opaque { univ_params, .. } => univ_params,
511        }
512    }
513    /// Get the value (if this is a definition/theorem/opaque).
514    pub fn value(&self) -> Option<&Expr> {
515        match self {
516            Declaration::Axiom { .. } => None,
517            Declaration::Definition { val, .. }
518            | Declaration::Theorem { val, .. }
519            | Declaration::Opaque { val, .. } => Some(val),
520        }
521    }
522    /// Get the reducibility hint.
523    pub fn reducibility_hint(&self) -> ReducibilityHint {
524        match self {
525            Declaration::Axiom { .. } => ReducibilityHint::Opaque,
526            Declaration::Definition { hint, .. } => *hint,
527            Declaration::Theorem { .. } | Declaration::Opaque { .. } => ReducibilityHint::Opaque,
528        }
529    }
530    /// Convert a legacy Declaration to ConstantInfo.
531    pub fn to_constant_info(&self) -> ConstantInfo {
532        match self {
533            Declaration::Axiom {
534                name,
535                univ_params,
536                ty,
537            } => ConstantInfo::Axiom(crate::declaration::AxiomVal {
538                common: ConstantVal {
539                    name: name.clone(),
540                    level_params: univ_params.clone(),
541                    ty: ty.clone(),
542                },
543                is_unsafe: false,
544            }),
545            Declaration::Definition {
546                name,
547                univ_params,
548                ty,
549                val,
550                hint,
551            } => ConstantInfo::Definition(DefinitionVal {
552                common: ConstantVal {
553                    name: name.clone(),
554                    level_params: univ_params.clone(),
555                    ty: ty.clone(),
556                },
557                value: val.clone(),
558                hints: *hint,
559                safety: DefinitionSafety::Safe,
560                all: vec![name.clone()],
561            }),
562            Declaration::Theorem {
563                name,
564                univ_params,
565                ty,
566                val,
567            } => ConstantInfo::Theorem(crate::declaration::TheoremVal {
568                common: ConstantVal {
569                    name: name.clone(),
570                    level_params: univ_params.clone(),
571                    ty: ty.clone(),
572                },
573                value: val.clone(),
574                all: vec![name.clone()],
575            }),
576            Declaration::Opaque {
577                name,
578                univ_params,
579                ty,
580                val,
581            } => ConstantInfo::Opaque(crate::declaration::OpaqueVal {
582                common: ConstantVal {
583                    name: name.clone(),
584                    level_params: univ_params.clone(),
585                    ty: ty.clone(),
586                },
587                value: val.clone(),
588                is_unsafe: false,
589                all: vec![name.clone()],
590            }),
591        }
592    }
593}
594/// A type-erased function pointer with arity tracking.
595#[allow(dead_code)]
596pub struct RawFnPtr {
597    /// The raw function pointer (stored as usize for type erasure).
598    ptr: usize,
599    arity: usize,
600    name: String,
601}
602#[allow(dead_code)]
603impl RawFnPtr {
604    /// Creates a new raw function pointer descriptor.
605    pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
606        Self {
607            ptr,
608            arity,
609            name: name.into(),
610        }
611    }
612    /// Returns the arity.
613    pub fn arity(&self) -> usize {
614        self.arity
615    }
616    /// Returns the name.
617    pub fn name(&self) -> &str {
618        &self.name
619    }
620    /// Returns the raw pointer value.
621    pub fn raw(&self) -> usize {
622        self.ptr
623    }
624}
625/// A trie-based prefix counter.
626#[allow(dead_code)]
627pub struct PrefixCounter {
628    children: std::collections::HashMap<char, PrefixCounter>,
629    count: usize,
630}
631#[allow(dead_code)]
632impl PrefixCounter {
633    /// Creates an empty prefix counter.
634    pub fn new() -> Self {
635        Self {
636            children: std::collections::HashMap::new(),
637            count: 0,
638        }
639    }
640    /// Records a string.
641    pub fn record(&mut self, s: &str) {
642        self.count += 1;
643        let mut node = self;
644        for c in s.chars() {
645            node = node.children.entry(c).or_default();
646            node.count += 1;
647        }
648    }
649    /// Returns how many strings have been recorded that start with `prefix`.
650    pub fn count_with_prefix(&self, prefix: &str) -> usize {
651        let mut node = self;
652        for c in prefix.chars() {
653            match node.children.get(&c) {
654                Some(n) => node = n,
655                None => return 0,
656            }
657        }
658        node.count
659    }
660}
661/// A simple mutable key-value store for test fixtures.
662#[allow(dead_code)]
663pub struct Fixture {
664    data: std::collections::HashMap<String, String>,
665}
666#[allow(dead_code)]
667impl Fixture {
668    /// Creates an empty fixture.
669    pub fn new() -> Self {
670        Self {
671            data: std::collections::HashMap::new(),
672        }
673    }
674    /// Sets a key.
675    pub fn set(&mut self, key: impl Into<String>, val: impl Into<String>) {
676        self.data.insert(key.into(), val.into());
677    }
678    /// Gets a value.
679    pub fn get(&self, key: &str) -> Option<&str> {
680        self.data.get(key).map(|s| s.as_str())
681    }
682    /// Returns the number of entries.
683    pub fn len(&self) -> usize {
684        self.data.len()
685    }
686    /// Returns whether the collection is empty.
687    pub fn is_empty(&self) -> bool {
688        self.len() == 0
689    }
690}
691/// A read-only view of the environment with aggregated queries.
692#[allow(dead_code)]
693pub struct EnvironmentView<'a> {
694    env: &'a Environment,
695}
696impl<'a> EnvironmentView<'a> {
697    /// Create a view over an environment.
698    #[allow(dead_code)]
699    pub fn new(env: &'a Environment) -> Self {
700        Self { env }
701    }
702    /// Get all axiom names.
703    #[allow(dead_code)]
704    pub fn axiom_names(&self) -> Vec<&Name> {
705        self.env
706            .constant_infos()
707            .filter_map(|(name, ci)| if ci.is_axiom() { Some(name) } else { None })
708            .collect()
709    }
710    /// Get all inductive type names.
711    #[allow(dead_code)]
712    pub fn inductive_names(&self) -> Vec<&Name> {
713        self.env
714            .constant_infos()
715            .filter_map(|(name, ci)| if ci.is_inductive() { Some(name) } else { None })
716            .collect()
717    }
718    /// Get all constructor names.
719    #[allow(dead_code)]
720    pub fn constructor_names(&self) -> Vec<&Name> {
721        self.env
722            .constant_infos()
723            .filter_map(|(name, ci)| {
724                if ci.is_constructor() {
725                    Some(name)
726                } else {
727                    None
728                }
729            })
730            .collect()
731    }
732    /// Get all definition names.
733    #[allow(dead_code)]
734    pub fn definition_names(&self) -> Vec<&Name> {
735        self.env
736            .constant_infos()
737            .filter_map(|(name, ci)| if ci.is_definition() { Some(name) } else { None })
738            .collect()
739    }
740    /// Count declarations by kind.
741    #[allow(dead_code)]
742    pub fn count_by_kind(&self) -> EnvKindCounts {
743        let mut counts = EnvKindCounts::default();
744        for (_, ci) in self.env.constant_infos() {
745            if ci.is_axiom() {
746                counts.axioms += 1;
747            } else if ci.is_inductive() {
748                counts.inductives += 1;
749            } else if ci.is_constructor() {
750                counts.constructors += 1;
751            } else if ci.is_recursor() {
752                counts.recursors += 1;
753            } else if ci.is_definition() {
754                counts.definitions += 1;
755            } else if ci.is_theorem() {
756                counts.theorems += 1;
757            } else {
758                counts.other += 1;
759            }
760        }
761        counts
762    }
763}
764/// A label set for a graph node.
765#[allow(dead_code)]
766pub struct LabelSet {
767    labels: Vec<String>,
768}
769#[allow(dead_code)]
770impl LabelSet {
771    /// Creates a new empty label set.
772    pub fn new() -> Self {
773        Self { labels: Vec::new() }
774    }
775    /// Adds a label (deduplicates).
776    pub fn add(&mut self, label: impl Into<String>) {
777        let s = label.into();
778        if !self.labels.contains(&s) {
779            self.labels.push(s);
780        }
781    }
782    /// Returns `true` if `label` is present.
783    pub fn has(&self, label: &str) -> bool {
784        self.labels.iter().any(|l| l == label)
785    }
786    /// Returns the count of labels.
787    pub fn count(&self) -> usize {
788        self.labels.len()
789    }
790    /// Returns all labels.
791    pub fn all(&self) -> &[String] {
792        &self.labels
793    }
794}
795/// Environment statistics summary.
796#[derive(Clone, Debug, Default)]
797pub struct EnvStats {
798    /// Total constants.
799    pub total: usize,
800    /// Axioms.
801    pub axioms: usize,
802    /// Definitions.
803    pub definitions: usize,
804    /// Theorems.
805    pub theorems: usize,
806    /// Inductive types.
807    pub inductives: usize,
808    /// Constructors.
809    pub constructors: usize,
810    /// Recursors.
811    pub recursors: usize,
812}
813/// A generic counter that tracks min/max/sum for statistical summaries.
814#[allow(dead_code)]
815pub struct StatSummary {
816    count: u64,
817    sum: f64,
818    min: f64,
819    max: f64,
820}
821#[allow(dead_code)]
822impl StatSummary {
823    /// Creates an empty summary.
824    pub fn new() -> Self {
825        Self {
826            count: 0,
827            sum: 0.0,
828            min: f64::INFINITY,
829            max: f64::NEG_INFINITY,
830        }
831    }
832    /// Records a sample.
833    pub fn record(&mut self, val: f64) {
834        self.count += 1;
835        self.sum += val;
836        if val < self.min {
837            self.min = val;
838        }
839        if val > self.max {
840            self.max = val;
841        }
842    }
843    /// Returns the mean, or `None` if no samples.
844    pub fn mean(&self) -> Option<f64> {
845        if self.count == 0 {
846            None
847        } else {
848            Some(self.sum / self.count as f64)
849        }
850    }
851    /// Returns the minimum, or `None` if no samples.
852    pub fn min(&self) -> Option<f64> {
853        if self.count == 0 {
854            None
855        } else {
856            Some(self.min)
857        }
858    }
859    /// Returns the maximum, or `None` if no samples.
860    pub fn max(&self) -> Option<f64> {
861        if self.count == 0 {
862            None
863        } else {
864            Some(self.max)
865        }
866    }
867    /// Returns the count of recorded samples.
868    pub fn count(&self) -> u64 {
869        self.count
870    }
871}
872/// A non-empty list (at least one element guaranteed).
873#[allow(dead_code)]
874pub struct NonEmptyVec<T> {
875    head: T,
876    tail: Vec<T>,
877}
878#[allow(dead_code)]
879impl<T> NonEmptyVec<T> {
880    /// Creates a non-empty vec with a single element.
881    pub fn singleton(val: T) -> Self {
882        Self {
883            head: val,
884            tail: Vec::new(),
885        }
886    }
887    /// Pushes an element.
888    pub fn push(&mut self, val: T) {
889        self.tail.push(val);
890    }
891    /// Returns a reference to the first element.
892    pub fn first(&self) -> &T {
893        &self.head
894    }
895    /// Returns a reference to the last element.
896    pub fn last(&self) -> &T {
897        self.tail.last().unwrap_or(&self.head)
898    }
899    /// Returns the number of elements.
900    pub fn len(&self) -> usize {
901        1 + self.tail.len()
902    }
903    /// Returns whether the collection is empty.
904    pub fn is_empty(&self) -> bool {
905        self.len() == 0
906    }
907    /// Returns all elements as a Vec.
908    pub fn to_vec(&self) -> Vec<&T> {
909        let mut v = vec![&self.head];
910        v.extend(self.tail.iter());
911        v
912    }
913}
914/// A counter that can measure elapsed time between snapshots.
915#[allow(dead_code)]
916pub struct Stopwatch {
917    start: crate::wall_clock::Instant,
918    splits: Vec<f64>,
919}
920#[allow(dead_code)]
921impl Stopwatch {
922    /// Creates and starts a new stopwatch.
923    pub fn start() -> Self {
924        Self {
925            start: crate::wall_clock::Instant::now(),
926            splits: Vec::new(),
927        }
928    }
929    /// Records a split time (elapsed since start).
930    pub fn split(&mut self) {
931        self.splits.push(self.elapsed_ms());
932    }
933    /// Returns total elapsed milliseconds since start.
934    pub fn elapsed_ms(&self) -> f64 {
935        self.start.elapsed().as_secs_f64() * 1000.0
936    }
937    /// Returns all recorded split times.
938    pub fn splits(&self) -> &[f64] {
939        &self.splits
940    }
941    /// Returns the number of splits.
942    pub fn num_splits(&self) -> usize {
943        self.splits.len()
944    }
945}
946/// A token bucket rate limiter.
947#[allow(dead_code)]
948pub struct TokenBucket {
949    capacity: u64,
950    tokens: u64,
951    refill_per_ms: u64,
952    last_refill: crate::wall_clock::Instant,
953}
954#[allow(dead_code)]
955impl TokenBucket {
956    /// Creates a new token bucket.
957    pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
958        Self {
959            capacity,
960            tokens: capacity,
961            refill_per_ms,
962            last_refill: crate::wall_clock::Instant::now(),
963        }
964    }
965    /// Attempts to consume `n` tokens.  Returns `true` on success.
966    pub fn try_consume(&mut self, n: u64) -> bool {
967        self.refill();
968        if self.tokens >= n {
969            self.tokens -= n;
970            true
971        } else {
972            false
973        }
974    }
975    fn refill(&mut self) {
976        let now = crate::wall_clock::Instant::now();
977        let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
978        if elapsed_ms > 0 {
979            let new_tokens = elapsed_ms * self.refill_per_ms;
980            self.tokens = (self.tokens + new_tokens).min(self.capacity);
981            self.last_refill = now;
982        }
983    }
984    /// Returns the number of currently available tokens.
985    pub fn available(&self) -> u64 {
986        self.tokens
987    }
988    /// Returns the bucket capacity.
989    pub fn capacity(&self) -> u64 {
990        self.capacity
991    }
992}
993/// A builder for incrementally constructing an `Environment`.
994#[allow(dead_code)]
995#[derive(Default)]
996pub struct EnvironmentBuilder {
997    declarations: Vec<Declaration>,
998    constants: Vec<crate::declaration::ConstantInfo>,
999}
1000impl EnvironmentBuilder {
1001    /// Create a new empty builder.
1002    #[allow(dead_code)]
1003    pub fn new() -> Self {
1004        Self::default()
1005    }
1006    /// Queue a legacy declaration for addition.
1007    #[allow(dead_code)]
1008    pub fn add_decl(mut self, decl: Declaration) -> Self {
1009        self.declarations.push(decl);
1010        self
1011    }
1012    /// Queue a ConstantInfo for addition.
1013    #[allow(dead_code)]
1014    pub fn add_constant(mut self, ci: crate::declaration::ConstantInfo) -> Self {
1015        self.constants.push(ci);
1016        self
1017    }
1018    /// Build the environment.
1019    #[allow(dead_code)]
1020    pub fn build(self) -> Result<Environment, EnvError> {
1021        let mut env = Environment::new();
1022        for decl in self.declarations {
1023            env.add(decl)?;
1024        }
1025        for ci in self.constants {
1026            env.add_constant(ci)?;
1027        }
1028        Ok(env)
1029    }
1030    /// Return the number of queued items.
1031    #[allow(dead_code)]
1032    pub fn len(&self) -> usize {
1033        self.declarations.len() + self.constants.len()
1034    }
1035    /// Check if the builder has nothing queued.
1036    #[allow(dead_code)]
1037    pub fn is_empty(&self) -> bool {
1038        self.declarations.is_empty() && self.constants.is_empty()
1039    }
1040}
1041/// A simple decision tree node for rule dispatching.
1042#[allow(dead_code)]
1043#[allow(missing_docs)]
1044pub enum DecisionNode {
1045    /// A leaf with an action string.
1046    Leaf(String),
1047    /// An interior node: check `key` equals `val` → `yes_branch`, else `no_branch`.
1048    Branch {
1049        key: String,
1050        val: String,
1051        yes_branch: Box<DecisionNode>,
1052        no_branch: Box<DecisionNode>,
1053    },
1054}
1055#[allow(dead_code)]
1056impl DecisionNode {
1057    /// Evaluates the decision tree with the given context.
1058    pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
1059        match self {
1060            DecisionNode::Leaf(action) => action.as_str(),
1061            DecisionNode::Branch {
1062                key,
1063                val,
1064                yes_branch,
1065                no_branch,
1066            } => {
1067                let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
1068                if actual == val.as_str() {
1069                    yes_branch.evaluate(ctx)
1070                } else {
1071                    no_branch.evaluate(ctx)
1072                }
1073            }
1074        }
1075    }
1076    /// Returns the depth of the decision tree.
1077    pub fn depth(&self) -> usize {
1078        match self {
1079            DecisionNode::Leaf(_) => 0,
1080            DecisionNode::Branch {
1081                yes_branch,
1082                no_branch,
1083                ..
1084            } => 1 + yes_branch.depth().max(no_branch.depth()),
1085        }
1086    }
1087}
1088/// A pool of reusable string buffers.
1089#[allow(dead_code)]
1090pub struct StringPool {
1091    free: Vec<String>,
1092}
1093#[allow(dead_code)]
1094impl StringPool {
1095    /// Creates a new empty string pool.
1096    pub fn new() -> Self {
1097        Self { free: Vec::new() }
1098    }
1099    /// Takes a string from the pool (may be empty).
1100    pub fn take(&mut self) -> String {
1101        self.free.pop().unwrap_or_default()
1102    }
1103    /// Returns a string to the pool.
1104    pub fn give(&mut self, mut s: String) {
1105        s.clear();
1106        self.free.push(s);
1107    }
1108    /// Returns the number of free strings in the pool.
1109    pub fn free_count(&self) -> usize {
1110        self.free.len()
1111    }
1112}
1113/// A tagged union for representing a simple two-case discriminated union.
1114#[allow(dead_code)]
1115pub enum Either2<A, B> {
1116    /// The first alternative.
1117    First(A),
1118    /// The second alternative.
1119    Second(B),
1120}
1121#[allow(dead_code)]
1122impl<A, B> Either2<A, B> {
1123    /// Returns `true` if this is the first alternative.
1124    pub fn is_first(&self) -> bool {
1125        matches!(self, Either2::First(_))
1126    }
1127    /// Returns `true` if this is the second alternative.
1128    pub fn is_second(&self) -> bool {
1129        matches!(self, Either2::Second(_))
1130    }
1131    /// Returns the first value if present.
1132    pub fn first(self) -> Option<A> {
1133        match self {
1134            Either2::First(a) => Some(a),
1135            _ => None,
1136        }
1137    }
1138    /// Returns the second value if present.
1139    pub fn second(self) -> Option<B> {
1140        match self {
1141            Either2::Second(b) => Some(b),
1142            _ => None,
1143        }
1144    }
1145    /// Maps over the first alternative.
1146    pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
1147        match self {
1148            Either2::First(a) => Either2::First(f(a)),
1149            Either2::Second(b) => Either2::Second(b),
1150        }
1151    }
1152}
1153/// A simple stack-based calculator for arithmetic expressions.
1154#[allow(dead_code)]
1155pub struct StackCalc {
1156    stack: Vec<i64>,
1157}
1158#[allow(dead_code)]
1159impl StackCalc {
1160    /// Creates a new empty calculator.
1161    pub fn new() -> Self {
1162        Self { stack: Vec::new() }
1163    }
1164    /// Pushes an integer literal.
1165    pub fn push(&mut self, n: i64) {
1166        self.stack.push(n);
1167    }
1168    /// Replaces the top two values, `b` on top of `a`, with `op(a, b)` and
1169    /// returns it.  Returns `None`, leaving the stack unchanged, if it holds
1170    /// fewer than two values.
1171    fn apply_binary(&mut self, op: impl FnOnce(i64, i64) -> i64) -> Option<i64> {
1172        let (rest_len, a, b) = match self.stack[..] {
1173            [ref rest @ .., a, b] => (rest.len(), a, b),
1174            _ => return None,
1175        };
1176        let value = op(a, b);
1177        self.stack.truncate(rest_len);
1178        self.stack.push(value);
1179        Some(value)
1180    }
1181    /// Adds the top two values and returns the sum, which replaces them.
1182    /// Returns `None`, leaving the stack unchanged, if it holds fewer than
1183    /// two values.
1184    pub fn add(&mut self) -> Option<i64> {
1185        self.apply_binary(|a, b| a + b)
1186    }
1187    /// Subtracts top from second and returns the difference, which replaces
1188    /// them.  Returns `None`, leaving the stack unchanged, if it holds fewer
1189    /// than two values.
1190    pub fn sub(&mut self) -> Option<i64> {
1191        self.apply_binary(|a, b| a - b)
1192    }
1193    /// Multiplies the top two values and returns the product, which replaces
1194    /// them.  Returns `None`, leaving the stack unchanged, if it holds fewer
1195    /// than two values.
1196    pub fn mul(&mut self) -> Option<i64> {
1197        self.apply_binary(|a, b| a * b)
1198    }
1199    /// Peeks the top value.
1200    pub fn peek(&self) -> Option<i64> {
1201        self.stack.last().copied()
1202    }
1203    /// Returns the stack depth.
1204    pub fn depth(&self) -> usize {
1205        self.stack.len()
1206    }
1207}
1208/// A fixed-size sliding window that computes a running sum.
1209#[allow(dead_code)]
1210pub struct SlidingSum {
1211    window: Vec<f64>,
1212    capacity: usize,
1213    pos: usize,
1214    sum: f64,
1215    count: usize,
1216}
1217#[allow(dead_code)]
1218impl SlidingSum {
1219    /// Creates a sliding sum with the given window size.
1220    pub fn new(capacity: usize) -> Self {
1221        Self {
1222            window: vec![0.0; capacity],
1223            capacity,
1224            pos: 0,
1225            sum: 0.0,
1226            count: 0,
1227        }
1228    }
1229    /// Adds a value to the window, removing the oldest if full.
1230    pub fn push(&mut self, val: f64) {
1231        let oldest = self.window[self.pos];
1232        self.sum -= oldest;
1233        self.sum += val;
1234        self.window[self.pos] = val;
1235        self.pos = (self.pos + 1) % self.capacity;
1236        if self.count < self.capacity {
1237            self.count += 1;
1238        }
1239    }
1240    /// Returns the current window sum.
1241    pub fn sum(&self) -> f64 {
1242        self.sum
1243    }
1244    /// Returns the window mean, or `None` if empty.
1245    pub fn mean(&self) -> Option<f64> {
1246        if self.count == 0 {
1247            None
1248        } else {
1249            Some(self.sum / self.count as f64)
1250        }
1251    }
1252    /// Returns the current window size (number of valid elements).
1253    pub fn count(&self) -> usize {
1254        self.count
1255    }
1256}
1257/// A reusable scratch buffer for path computations.
1258#[allow(dead_code)]
1259pub struct PathBuf {
1260    components: Vec<String>,
1261}
1262#[allow(dead_code)]
1263impl PathBuf {
1264    /// Creates a new empty path buffer.
1265    pub fn new() -> Self {
1266        Self {
1267            components: Vec::new(),
1268        }
1269    }
1270    /// Pushes a component.
1271    pub fn push(&mut self, comp: impl Into<String>) {
1272        self.components.push(comp.into());
1273    }
1274    /// Pops the last component.
1275    pub fn pop(&mut self) {
1276        self.components.pop();
1277    }
1278    /// Returns the current path as a `/`-separated string.
1279    pub fn as_str(&self) -> String {
1280        self.components.join("/")
1281    }
1282    /// Returns the depth of the path.
1283    pub fn depth(&self) -> usize {
1284        self.components.len()
1285    }
1286    /// Clears the path.
1287    pub fn clear(&mut self) {
1288        self.components.clear();
1289    }
1290}
1291/// A flat list of substitution pairs `(from, to)`.
1292#[allow(dead_code)]
1293pub struct FlatSubstitution {
1294    pairs: Vec<(String, String)>,
1295}
1296#[allow(dead_code)]
1297impl FlatSubstitution {
1298    /// Creates an empty substitution.
1299    pub fn new() -> Self {
1300        Self { pairs: Vec::new() }
1301    }
1302    /// Adds a pair.
1303    pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
1304        self.pairs.push((from.into(), to.into()));
1305    }
1306    /// Applies all substitutions to `s` (leftmost-first order).
1307    pub fn apply(&self, s: &str) -> String {
1308        let mut result = s.to_string();
1309        for (from, to) in &self.pairs {
1310            result = result.replace(from.as_str(), to.as_str());
1311        }
1312        result
1313    }
1314    /// Returns the number of pairs.
1315    pub fn len(&self) -> usize {
1316        self.pairs.len()
1317    }
1318    /// Returns `true` if empty.
1319    pub fn is_empty(&self) -> bool {
1320        self.pairs.is_empty()
1321    }
1322}
1323/// Errors that can occur when working with the environment.
1324#[derive(Clone, Debug)]
1325pub enum EnvError {
1326    /// A declaration with this name already exists
1327    DuplicateDeclaration(Name),
1328    /// The declaration was not found
1329    NotFound(Name),
1330    /// A quotient-related precondition failed (e.g. quotients already
1331    /// initialized, `Eq` missing or malformed, or an attempt to add a
1332    /// `ConstantInfo::Quotient` outside of [`Environment::add_quot`]).
1333    InvalidQuotient(String),
1334}
1335/// A pair of `StatSummary` values tracking before/after a transformation.
1336#[allow(dead_code)]
1337pub struct TransformStat {
1338    before: StatSummary,
1339    after: StatSummary,
1340}
1341#[allow(dead_code)]
1342impl TransformStat {
1343    /// Creates a new transform stat recorder.
1344    pub fn new() -> Self {
1345        Self {
1346            before: StatSummary::new(),
1347            after: StatSummary::new(),
1348        }
1349    }
1350    /// Records a before value.
1351    pub fn record_before(&mut self, v: f64) {
1352        self.before.record(v);
1353    }
1354    /// Records an after value.
1355    pub fn record_after(&mut self, v: f64) {
1356        self.after.record(v);
1357    }
1358    /// Returns the mean reduction ratio (after/before).
1359    pub fn mean_ratio(&self) -> Option<f64> {
1360        let b = self.before.mean()?;
1361        let a = self.after.mean()?;
1362        if b.abs() < f64::EPSILON {
1363            return None;
1364        }
1365        Some(a / b)
1366    }
1367}
1368/// A dependency closure builder (transitive closure via BFS).
1369#[allow(dead_code)]
1370pub struct TransitiveClosure {
1371    adj: Vec<Vec<usize>>,
1372    n: usize,
1373}
1374#[allow(dead_code)]
1375impl TransitiveClosure {
1376    /// Creates a transitive closure builder for `n` nodes.
1377    pub fn new(n: usize) -> Self {
1378        Self {
1379            adj: vec![Vec::new(); n],
1380            n,
1381        }
1382    }
1383    /// Adds a direct edge.
1384    pub fn add_edge(&mut self, from: usize, to: usize) {
1385        if from < self.n {
1386            self.adj[from].push(to);
1387        }
1388    }
1389    /// Computes all nodes reachable from `start` (including `start`).
1390    pub fn reachable_from(&self, start: usize) -> Vec<usize> {
1391        let mut visited = vec![false; self.n];
1392        let mut queue = std::collections::VecDeque::new();
1393        queue.push_back(start);
1394        while let Some(node) = queue.pop_front() {
1395            if node >= self.n || visited[node] {
1396                continue;
1397            }
1398            visited[node] = true;
1399            for &next in &self.adj[node] {
1400                queue.push_back(next);
1401            }
1402        }
1403        (0..self.n).filter(|&i| visited[i]).collect()
1404    }
1405    /// Returns `true` if `from` can transitively reach `to`.
1406    pub fn can_reach(&self, from: usize, to: usize) -> bool {
1407        self.reachable_from(from).contains(&to)
1408    }
1409}
1410/// A min-heap implemented as a binary heap.
1411#[allow(dead_code)]
1412pub struct MinHeap<T: Ord> {
1413    data: Vec<T>,
1414}
1415#[allow(dead_code)]
1416impl<T: Ord> MinHeap<T> {
1417    /// Creates a new empty min-heap.
1418    pub fn new() -> Self {
1419        Self { data: Vec::new() }
1420    }
1421    /// Inserts an element.
1422    pub fn push(&mut self, val: T) {
1423        self.data.push(val);
1424        self.sift_up(self.data.len() - 1);
1425    }
1426    /// Removes and returns the minimum element.
1427    pub fn pop(&mut self) -> Option<T> {
1428        if self.data.is_empty() {
1429            return None;
1430        }
1431        let n = self.data.len();
1432        self.data.swap(0, n - 1);
1433        let min = self.data.pop();
1434        if !self.data.is_empty() {
1435            self.sift_down(0);
1436        }
1437        min
1438    }
1439    /// Returns a reference to the minimum element.
1440    pub fn peek(&self) -> Option<&T> {
1441        self.data.first()
1442    }
1443    /// Returns the number of elements.
1444    pub fn len(&self) -> usize {
1445        self.data.len()
1446    }
1447    /// Returns `true` if empty.
1448    pub fn is_empty(&self) -> bool {
1449        self.data.is_empty()
1450    }
1451    fn sift_up(&mut self, mut i: usize) {
1452        while i > 0 {
1453            let parent = (i - 1) / 2;
1454            if self.data[i] < self.data[parent] {
1455                self.data.swap(i, parent);
1456                i = parent;
1457            } else {
1458                break;
1459            }
1460        }
1461    }
1462    fn sift_down(&mut self, mut i: usize) {
1463        let n = self.data.len();
1464        loop {
1465            let left = 2 * i + 1;
1466            let right = 2 * i + 2;
1467            let mut smallest = i;
1468            if left < n && self.data[left] < self.data[smallest] {
1469                smallest = left;
1470            }
1471            if right < n && self.data[right] < self.data[smallest] {
1472                smallest = right;
1473            }
1474            if smallest == i {
1475                break;
1476            }
1477            self.data.swap(i, smallest);
1478            i = smallest;
1479        }
1480    }
1481}
1482/// A hierarchical configuration tree.
1483#[allow(dead_code)]
1484pub struct ConfigNode {
1485    key: String,
1486    value: Option<String>,
1487    children: Vec<ConfigNode>,
1488}
1489#[allow(dead_code)]
1490impl ConfigNode {
1491    /// Creates a leaf config node with a value.
1492    pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
1493        Self {
1494            key: key.into(),
1495            value: Some(value.into()),
1496            children: Vec::new(),
1497        }
1498    }
1499    /// Creates a section node with children.
1500    pub fn section(key: impl Into<String>) -> Self {
1501        Self {
1502            key: key.into(),
1503            value: None,
1504            children: Vec::new(),
1505        }
1506    }
1507    /// Adds a child node.
1508    pub fn add_child(&mut self, child: ConfigNode) {
1509        self.children.push(child);
1510    }
1511    /// Returns the key.
1512    pub fn key(&self) -> &str {
1513        &self.key
1514    }
1515    /// Returns the value, or `None` for section nodes.
1516    pub fn value(&self) -> Option<&str> {
1517        self.value.as_deref()
1518    }
1519    /// Returns the number of children.
1520    pub fn num_children(&self) -> usize {
1521        self.children.len()
1522    }
1523    /// Looks up a dot-separated path.
1524    pub fn lookup(&self, path: &str) -> Option<&str> {
1525        let mut parts = path.splitn(2, '.');
1526        let head = parts.next()?;
1527        let tail = parts.next();
1528        if head != self.key {
1529            return None;
1530        }
1531        match tail {
1532            None => self.value.as_deref(),
1533            Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1534        }
1535    }
1536    fn lookup_relative(&self, path: &str) -> Option<&str> {
1537        let mut parts = path.splitn(2, '.');
1538        let head = parts.next()?;
1539        let tail = parts.next();
1540        if head != self.key {
1541            return None;
1542        }
1543        match tail {
1544            None => self.value.as_deref(),
1545            Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1546        }
1547    }
1548}
1549/// A snapshot of an `Environment` at a point in time.
1550///
1551/// Snapshots are useful for implementing undo/redo in interactive mode.
1552#[derive(Clone, Debug)]
1553pub struct EnvironmentSnapshot {
1554    /// Names present at snapshot time, in insertion order.
1555    pub names: Vec<Name>,
1556}
1557impl EnvironmentSnapshot {
1558    /// Create a snapshot from an environment.
1559    pub fn from_env(env: &Environment) -> Self {
1560        let names: Vec<Name> = env.constant_names().cloned().collect();
1561        Self { names }
1562    }
1563    /// Number of constants in the snapshot.
1564    pub fn len(&self) -> usize {
1565        self.names.len()
1566    }
1567    /// Check if empty.
1568    pub fn is_empty(&self) -> bool {
1569        self.names.is_empty()
1570    }
1571    /// Return the names added in `new` that were not in `self`.
1572    pub fn diff<'a>(&self, new: &'a EnvironmentSnapshot) -> Vec<&'a Name> {
1573        new.names
1574            .iter()
1575            .filter(|n| !self.names.contains(n))
1576            .collect()
1577    }
1578}
1579/// A simple key-value store backed by a sorted Vec for small maps.
1580#[allow(dead_code)]
1581pub struct SmallMap<K: Ord + Clone, V: Clone> {
1582    entries: Vec<(K, V)>,
1583}
1584#[allow(dead_code)]
1585impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
1586    /// Creates a new empty small map.
1587    pub fn new() -> Self {
1588        Self {
1589            entries: Vec::new(),
1590        }
1591    }
1592    /// Inserts or replaces the value for `key`.
1593    pub fn insert(&mut self, key: K, val: V) {
1594        match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
1595            Ok(i) => self.entries[i].1 = val,
1596            Err(i) => self.entries.insert(i, (key, val)),
1597        }
1598    }
1599    /// Returns the value for `key`, or `None`.
1600    pub fn get(&self, key: &K) -> Option<&V> {
1601        self.entries
1602            .binary_search_by_key(&key, |(k, _)| k)
1603            .ok()
1604            .map(|i| &self.entries[i].1)
1605    }
1606    /// Returns the number of entries.
1607    pub fn len(&self) -> usize {
1608        self.entries.len()
1609    }
1610    /// Returns `true` if empty.
1611    pub fn is_empty(&self) -> bool {
1612        self.entries.is_empty()
1613    }
1614    /// Returns all keys.
1615    pub fn keys(&self) -> Vec<&K> {
1616        self.entries.iter().map(|(k, _)| k).collect()
1617    }
1618    /// Returns all values.
1619    pub fn values(&self) -> Vec<&V> {
1620        self.entries.iter().map(|(_, v)| v).collect()
1621    }
1622}
1623/// A simple directed acyclic graph.
1624#[allow(dead_code)]
1625pub struct SimpleDag {
1626    /// `edges[i]` is the list of direct successors of node `i`.
1627    edges: Vec<Vec<usize>>,
1628}
1629#[allow(dead_code)]
1630impl SimpleDag {
1631    /// Creates a DAG with `n` nodes and no edges.
1632    pub fn new(n: usize) -> Self {
1633        Self {
1634            edges: vec![Vec::new(); n],
1635        }
1636    }
1637    /// Adds an edge from `from` to `to`.
1638    pub fn add_edge(&mut self, from: usize, to: usize) {
1639        if from < self.edges.len() {
1640            self.edges[from].push(to);
1641        }
1642    }
1643    /// Returns the successors of `node`.
1644    pub fn successors(&self, node: usize) -> &[usize] {
1645        self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
1646    }
1647    /// Returns `true` if `from` can reach `to` via DFS.
1648    pub fn can_reach(&self, from: usize, to: usize) -> bool {
1649        let mut visited = vec![false; self.edges.len()];
1650        self.dfs(from, to, &mut visited)
1651    }
1652    fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
1653        if cur == target {
1654            return true;
1655        }
1656        if cur >= visited.len() || visited[cur] {
1657            return false;
1658        }
1659        visited[cur] = true;
1660        for &next in self.successors(cur) {
1661            if self.dfs(next, target, visited) {
1662                return true;
1663            }
1664        }
1665        false
1666    }
1667    /// Returns the topological order of nodes, or `None` if a cycle is detected.
1668    pub fn topological_sort(&self) -> Option<Vec<usize>> {
1669        let n = self.edges.len();
1670        let mut in_degree = vec![0usize; n];
1671        for succs in &self.edges {
1672            for &s in succs {
1673                if s < n {
1674                    in_degree[s] += 1;
1675                }
1676            }
1677        }
1678        let mut queue: std::collections::VecDeque<usize> =
1679            (0..n).filter(|&i| in_degree[i] == 0).collect();
1680        let mut order = Vec::new();
1681        while let Some(node) = queue.pop_front() {
1682            order.push(node);
1683            for &s in self.successors(node) {
1684                if s < n {
1685                    in_degree[s] -= 1;
1686                    if in_degree[s] == 0 {
1687                        queue.push_back(s);
1688                    }
1689                }
1690            }
1691        }
1692        if order.len() == n {
1693            Some(order)
1694        } else {
1695            None
1696        }
1697    }
1698    /// Returns the number of nodes.
1699    pub fn num_nodes(&self) -> usize {
1700        self.edges.len()
1701    }
1702}
1703/// A write-once cell.
1704#[allow(dead_code)]
1705pub struct WriteOnce<T> {
1706    value: std::cell::Cell<Option<T>>,
1707}
1708#[allow(dead_code)]
1709impl<T: Copy> WriteOnce<T> {
1710    /// Creates an empty write-once cell.
1711    pub fn new() -> Self {
1712        Self {
1713            value: std::cell::Cell::new(None),
1714        }
1715    }
1716    /// Writes a value.  Returns `false` if already written.
1717    pub fn write(&self, val: T) -> bool {
1718        if self.value.get().is_some() {
1719            return false;
1720        }
1721        self.value.set(Some(val));
1722        true
1723    }
1724    /// Returns the value if written.
1725    pub fn read(&self) -> Option<T> {
1726        self.value.get()
1727    }
1728    /// Returns `true` if the value has been written.
1729    pub fn is_written(&self) -> bool {
1730        self.value.get().is_some()
1731    }
1732}