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