Skip to main content

oxilean_kernel/context/
types.rs

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