Skip to main content

oxilean_kernel/instantiate/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use crate::Node;
6use crate::{Expr, FVarId, Level, Name};
7use std::rc::Rc;
8
9use std::collections::HashMap;
10
11use super::functions::{instantiate_many, named_subst_apply};
12
13/// A telescope is a sequence of (name, type) binders, where later types
14/// may depend on earlier names.
15///
16/// This is the standard way to represent the argument list of a function
17/// type `(x₁ : T₁) → (x₂ : T₂[x₁]) → … → B`.
18#[derive(Clone, Debug, Default)]
19pub struct Telescope {
20    /// Binders in order from outermost to innermost.
21    pub binders: Vec<(Name, Expr)>,
22}
23impl Telescope {
24    /// Create an empty telescope.
25    pub fn new() -> Self {
26        Self::default()
27    }
28    /// Add a binder to the end of the telescope.
29    pub fn push(&mut self, name: Name, ty: Expr) {
30        self.binders.push((name, ty));
31    }
32    /// Return the length of the telescope.
33    pub fn len(&self) -> usize {
34        self.binders.len()
35    }
36    /// Check if the telescope is empty.
37    pub fn is_empty(&self) -> bool {
38        self.binders.is_empty()
39    }
40    /// Extract the telescope from a Pi type.
41    ///
42    /// `telescope_of(Pi(x: A, Pi(y: B, C)))` returns `[(x, A), (y, B)]` and body `C`.
43    pub fn from_pi(expr: &Expr) -> (Self, Expr) {
44        let mut tel = Telescope::new();
45        let mut cur = expr;
46        while let Expr::Pi(_, name, ty, body) = cur {
47            tel.push(name.clone(), (**ty).clone());
48            cur = body;
49        }
50        (tel, cur.clone())
51    }
52    /// Reconstruct the Pi type from this telescope and a body.
53    pub fn to_pi(&self, body: Expr) -> Expr {
54        self.binders.iter().rev().fold(body, |acc, (name, ty)| {
55            Expr::Pi(
56                crate::BinderInfo::Default,
57                name.clone(),
58                Node::new(ty.clone()),
59                Node::new(acc),
60            )
61        })
62    }
63    /// Reconstruct a Lambda from this telescope and a body.
64    pub fn to_lam(&self, body: Expr) -> Expr {
65        self.binders.iter().rev().fold(body, |acc, (name, ty)| {
66            Expr::Lam(
67                crate::BinderInfo::Default,
68                name.clone(),
69                Node::new(ty.clone()),
70                Node::new(acc),
71            )
72        })
73    }
74    /// Instantiate the telescope with a list of expressions.
75    ///
76    /// Returns the types with de Bruijn indices resolved.
77    pub fn instantiate(&self, args: &[Expr]) -> Vec<Expr> {
78        let mut result = Vec::new();
79        for (i, (_, ty)) in self.binders.iter().enumerate() {
80            let subst = &args[..i.min(args.len())];
81            let inst = instantiate_many(ty, subst);
82            result.push(inst);
83        }
84        result
85    }
86}
87/// A sparse vector: stores only non-default elements.
88#[allow(dead_code)]
89pub struct SparseVec<T: Default + Clone + PartialEq> {
90    entries: std::collections::HashMap<usize, T>,
91    default_: T,
92    logical_len: usize,
93}
94#[allow(dead_code)]
95impl<T: Default + Clone + PartialEq> SparseVec<T> {
96    /// Creates a new sparse vector with logical length `len`.
97    pub fn new(len: usize) -> Self {
98        Self {
99            entries: std::collections::HashMap::new(),
100            default_: T::default(),
101            logical_len: len,
102        }
103    }
104    /// Sets element at `idx`.
105    pub fn set(&mut self, idx: usize, val: T) {
106        if val == self.default_ {
107            self.entries.remove(&idx);
108        } else {
109            self.entries.insert(idx, val);
110        }
111    }
112    /// Gets element at `idx`.
113    pub fn get(&self, idx: usize) -> &T {
114        self.entries.get(&idx).unwrap_or(&self.default_)
115    }
116    /// Returns the logical length.
117    pub fn len(&self) -> usize {
118        self.logical_len
119    }
120    /// Returns whether the collection is empty.
121    pub fn is_empty(&self) -> bool {
122        self.len() == 0
123    }
124    /// Returns the number of non-default elements.
125    pub fn nnz(&self) -> usize {
126        self.entries.len()
127    }
128}
129/// A simple mutable key-value store for test fixtures.
130#[allow(dead_code)]
131pub struct Fixture {
132    data: std::collections::HashMap<String, String>,
133}
134#[allow(dead_code)]
135impl Fixture {
136    /// Creates an empty fixture.
137    pub fn new() -> Self {
138        Self {
139            data: std::collections::HashMap::new(),
140        }
141    }
142    /// Sets a key.
143    pub fn set(&mut self, key: impl Into<String>, val: impl Into<String>) {
144        self.data.insert(key.into(), val.into());
145    }
146    /// Gets a value.
147    pub fn get(&self, key: &str) -> Option<&str> {
148        self.data.get(key).map(|s| s.as_str())
149    }
150    /// Returns the number of entries.
151    pub fn len(&self) -> usize {
152        self.data.len()
153    }
154    /// Returns whether the collection is empty.
155    pub fn is_empty(&self) -> bool {
156        self.len() == 0
157    }
158}
159/// A set of rewrite rules.
160#[allow(dead_code)]
161pub struct RewriteRuleSet {
162    rules: Vec<RewriteRule>,
163}
164#[allow(dead_code)]
165impl RewriteRuleSet {
166    /// Creates an empty rule set.
167    pub fn new() -> Self {
168        Self { rules: Vec::new() }
169    }
170    /// Adds a rule.
171    pub fn add(&mut self, rule: RewriteRule) {
172        self.rules.push(rule);
173    }
174    /// Returns the number of rules.
175    pub fn len(&self) -> usize {
176        self.rules.len()
177    }
178    /// Returns `true` if the set is empty.
179    pub fn is_empty(&self) -> bool {
180        self.rules.is_empty()
181    }
182    /// Returns all conditional rules.
183    pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
184        self.rules.iter().filter(|r| r.conditional).collect()
185    }
186    /// Returns all unconditional rules.
187    pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
188        self.rules.iter().filter(|r| !r.conditional).collect()
189    }
190    /// Looks up a rule by name.
191    pub fn get(&self, name: &str) -> Option<&RewriteRule> {
192        self.rules.iter().find(|r| r.name == name)
193    }
194}
195/// A label set for a graph node.
196#[allow(dead_code)]
197pub struct LabelSet {
198    labels: Vec<String>,
199}
200#[allow(dead_code)]
201impl LabelSet {
202    /// Creates a new empty label set.
203    pub fn new() -> Self {
204        Self { labels: Vec::new() }
205    }
206    /// Adds a label (deduplicates).
207    pub fn add(&mut self, label: impl Into<String>) {
208        let s = label.into();
209        if !self.labels.contains(&s) {
210            self.labels.push(s);
211        }
212    }
213    /// Returns `true` if `label` is present.
214    pub fn has(&self, label: &str) -> bool {
215        self.labels.iter().any(|l| l == label)
216    }
217    /// Returns the count of labels.
218    pub fn count(&self) -> usize {
219        self.labels.len()
220    }
221    /// Returns all labels.
222    pub fn all(&self) -> &[String] {
223        &self.labels
224    }
225}
226/// A window iterator that yields overlapping windows of size `n`.
227#[allow(dead_code)]
228pub struct WindowIterator<'a, T> {
229    pub(super) data: &'a [T],
230    pub(super) pos: usize,
231    pub(super) window: usize,
232}
233#[allow(dead_code)]
234impl<'a, T> WindowIterator<'a, T> {
235    /// Creates a new window iterator.
236    pub fn new(data: &'a [T], window: usize) -> Self {
237        Self {
238            data,
239            pos: 0,
240            window,
241        }
242    }
243}
244/// A flat list of substitution pairs `(from, to)`.
245#[allow(dead_code)]
246pub struct FlatSubstitution {
247    pairs: Vec<(String, String)>,
248}
249#[allow(dead_code)]
250impl FlatSubstitution {
251    /// Creates an empty substitution.
252    pub fn new() -> Self {
253        Self { pairs: Vec::new() }
254    }
255    /// Adds a pair.
256    pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
257        self.pairs.push((from.into(), to.into()));
258    }
259    /// Applies all substitutions to `s` (leftmost-first order).
260    pub fn apply(&self, s: &str) -> String {
261        let mut result = s.to_string();
262        for (from, to) in &self.pairs {
263            result = result.replace(from.as_str(), to.as_str());
264        }
265        result
266    }
267    /// Returns the number of pairs.
268    pub fn len(&self) -> usize {
269        self.pairs.len()
270    }
271    /// Returns `true` if empty.
272    pub fn is_empty(&self) -> bool {
273        self.pairs.is_empty()
274    }
275}
276/// A pool of reusable string buffers.
277#[allow(dead_code)]
278pub struct StringPool {
279    free: Vec<String>,
280}
281#[allow(dead_code)]
282impl StringPool {
283    /// Creates a new empty string pool.
284    pub fn new() -> Self {
285        Self { free: Vec::new() }
286    }
287    /// Takes a string from the pool (may be empty).
288    pub fn take(&mut self) -> String {
289        self.free.pop().unwrap_or_default()
290    }
291    /// Returns a string to the pool.
292    pub fn give(&mut self, mut s: String) {
293        s.clear();
294        self.free.push(s);
295    }
296    /// Returns the number of free strings in the pool.
297    pub fn free_count(&self) -> usize {
298        self.free.len()
299    }
300}
301/// A non-empty list (at least one element guaranteed).
302#[allow(dead_code)]
303pub struct NonEmptyVec<T> {
304    head: T,
305    tail: Vec<T>,
306}
307#[allow(dead_code)]
308impl<T> NonEmptyVec<T> {
309    /// Creates a non-empty vec with a single element.
310    pub fn singleton(val: T) -> Self {
311        Self {
312            head: val,
313            tail: Vec::new(),
314        }
315    }
316    /// Pushes an element.
317    pub fn push(&mut self, val: T) {
318        self.tail.push(val);
319    }
320    /// Returns a reference to the first element.
321    pub fn first(&self) -> &T {
322        &self.head
323    }
324    /// Returns a reference to the last element.
325    pub fn last(&self) -> &T {
326        self.tail.last().unwrap_or(&self.head)
327    }
328    /// Returns the number of elements.
329    pub fn len(&self) -> usize {
330        1 + self.tail.len()
331    }
332    /// Returns whether the collection is empty.
333    pub fn is_empty(&self) -> bool {
334        self.len() == 0
335    }
336    /// Returns all elements as a Vec.
337    pub fn to_vec(&self) -> Vec<&T> {
338        let mut v = vec![&self.head];
339        v.extend(self.tail.iter());
340        v
341    }
342}
343/// A simple key-value store backed by a sorted Vec for small maps.
344#[allow(dead_code)]
345pub struct SmallMap<K: Ord + Clone, V: Clone> {
346    entries: Vec<(K, V)>,
347}
348#[allow(dead_code)]
349impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
350    /// Creates a new empty small map.
351    pub fn new() -> Self {
352        Self {
353            entries: Vec::new(),
354        }
355    }
356    /// Inserts or replaces the value for `key`.
357    pub fn insert(&mut self, key: K, val: V) {
358        match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
359            Ok(i) => self.entries[i].1 = val,
360            Err(i) => self.entries.insert(i, (key, val)),
361        }
362    }
363    /// Returns the value for `key`, or `None`.
364    pub fn get(&self, key: &K) -> Option<&V> {
365        self.entries
366            .binary_search_by_key(&key, |(k, _)| k)
367            .ok()
368            .map(|i| &self.entries[i].1)
369    }
370    /// Returns the number of entries.
371    pub fn len(&self) -> usize {
372        self.entries.len()
373    }
374    /// Returns `true` if empty.
375    pub fn is_empty(&self) -> bool {
376        self.entries.is_empty()
377    }
378    /// Returns all keys.
379    pub fn keys(&self) -> Vec<&K> {
380        self.entries.iter().map(|(k, _)| k).collect()
381    }
382    /// Returns all values.
383    pub fn values(&self) -> Vec<&V> {
384        self.entries.iter().map(|(_, v)| v).collect()
385    }
386}
387/// A generic counter that tracks min/max/sum for statistical summaries.
388#[allow(dead_code)]
389pub struct StatSummary {
390    count: u64,
391    sum: f64,
392    min: f64,
393    max: f64,
394}
395#[allow(dead_code)]
396impl StatSummary {
397    /// Creates an empty summary.
398    pub fn new() -> Self {
399        Self {
400            count: 0,
401            sum: 0.0,
402            min: f64::INFINITY,
403            max: f64::NEG_INFINITY,
404        }
405    }
406    /// Records a sample.
407    pub fn record(&mut self, val: f64) {
408        self.count += 1;
409        self.sum += val;
410        if val < self.min {
411            self.min = val;
412        }
413        if val > self.max {
414            self.max = val;
415        }
416    }
417    /// Returns the mean, or `None` if no samples.
418    pub fn mean(&self) -> Option<f64> {
419        if self.count == 0 {
420            None
421        } else {
422            Some(self.sum / self.count as f64)
423        }
424    }
425    /// Returns the minimum, or `None` if no samples.
426    pub fn min(&self) -> Option<f64> {
427        if self.count == 0 {
428            None
429        } else {
430            Some(self.min)
431        }
432    }
433    /// Returns the maximum, or `None` if no samples.
434    pub fn max(&self) -> Option<f64> {
435        if self.count == 0 {
436            None
437        } else {
438            Some(self.max)
439        }
440    }
441    /// Returns the count of recorded samples.
442    pub fn count(&self) -> u64 {
443        self.count
444    }
445}
446/// A min-heap implemented as a binary heap.
447#[allow(dead_code)]
448pub struct MinHeap<T: Ord> {
449    data: Vec<T>,
450}
451#[allow(dead_code)]
452impl<T: Ord> MinHeap<T> {
453    /// Creates a new empty min-heap.
454    pub fn new() -> Self {
455        Self { data: Vec::new() }
456    }
457    /// Inserts an element.
458    pub fn push(&mut self, val: T) {
459        self.data.push(val);
460        self.sift_up(self.data.len() - 1);
461    }
462    /// Removes and returns the minimum element.
463    pub fn pop(&mut self) -> Option<T> {
464        if self.data.is_empty() {
465            return None;
466        }
467        let n = self.data.len();
468        self.data.swap(0, n - 1);
469        let min = self.data.pop();
470        if !self.data.is_empty() {
471            self.sift_down(0);
472        }
473        min
474    }
475    /// Returns a reference to the minimum element.
476    pub fn peek(&self) -> Option<&T> {
477        self.data.first()
478    }
479    /// Returns the number of elements.
480    pub fn len(&self) -> usize {
481        self.data.len()
482    }
483    /// Returns `true` if empty.
484    pub fn is_empty(&self) -> bool {
485        self.data.is_empty()
486    }
487    fn sift_up(&mut self, mut i: usize) {
488        while i > 0 {
489            let parent = (i - 1) / 2;
490            if self.data[i] < self.data[parent] {
491                self.data.swap(i, parent);
492                i = parent;
493            } else {
494                break;
495            }
496        }
497    }
498    fn sift_down(&mut self, mut i: usize) {
499        let n = self.data.len();
500        loop {
501            let left = 2 * i + 1;
502            let right = 2 * i + 2;
503            let mut smallest = i;
504            if left < n && self.data[left] < self.data[smallest] {
505                smallest = left;
506            }
507            if right < n && self.data[right] < self.data[smallest] {
508                smallest = right;
509            }
510            if smallest == i {
511                break;
512            }
513            self.data.swap(i, smallest);
514            i = smallest;
515        }
516    }
517}
518/// Represents a rewrite rule `lhs → rhs`.
519#[allow(dead_code)]
520#[allow(missing_docs)]
521pub struct RewriteRule {
522    /// The name of the rule.
523    pub name: String,
524    /// A string representation of the LHS pattern.
525    pub lhs: String,
526    /// A string representation of the RHS.
527    pub rhs: String,
528    /// Whether this is a conditional rule (has side conditions).
529    pub conditional: bool,
530}
531#[allow(dead_code)]
532impl RewriteRule {
533    /// Creates an unconditional rewrite rule.
534    pub fn unconditional(
535        name: impl Into<String>,
536        lhs: impl Into<String>,
537        rhs: impl Into<String>,
538    ) -> Self {
539        Self {
540            name: name.into(),
541            lhs: lhs.into(),
542            rhs: rhs.into(),
543            conditional: false,
544        }
545    }
546    /// Creates a conditional rewrite rule.
547    pub fn conditional(
548        name: impl Into<String>,
549        lhs: impl Into<String>,
550        rhs: impl Into<String>,
551    ) -> Self {
552        Self {
553            name: name.into(),
554            lhs: lhs.into(),
555            rhs: rhs.into(),
556            conditional: true,
557        }
558    }
559    /// Returns a textual representation.
560    pub fn display(&self) -> String {
561        format!("{}: {} → {}", self.name, self.lhs, self.rhs)
562    }
563}
564/// A dependency closure builder (transitive closure via BFS).
565#[allow(dead_code)]
566pub struct TransitiveClosure {
567    adj: Vec<Vec<usize>>,
568    n: usize,
569}
570#[allow(dead_code)]
571impl TransitiveClosure {
572    /// Creates a transitive closure builder for `n` nodes.
573    pub fn new(n: usize) -> Self {
574        Self {
575            adj: vec![Vec::new(); n],
576            n,
577        }
578    }
579    /// Adds a direct edge.
580    pub fn add_edge(&mut self, from: usize, to: usize) {
581        if from < self.n {
582            self.adj[from].push(to);
583        }
584    }
585    /// Computes all nodes reachable from `start` (including `start`).
586    pub fn reachable_from(&self, start: usize) -> Vec<usize> {
587        let mut visited = vec![false; self.n];
588        let mut queue = std::collections::VecDeque::new();
589        queue.push_back(start);
590        while let Some(node) = queue.pop_front() {
591            if node >= self.n || visited[node] {
592                continue;
593            }
594            visited[node] = true;
595            for &next in &self.adj[node] {
596                queue.push_back(next);
597            }
598        }
599        (0..self.n).filter(|&i| visited[i]).collect()
600    }
601    /// Returns `true` if `from` can transitively reach `to`.
602    pub fn can_reach(&self, from: usize, to: usize) -> bool {
603        self.reachable_from(from).contains(&to)
604    }
605}
606/// A reusable scratch buffer for path computations.
607#[allow(dead_code)]
608pub struct PathBuf {
609    components: Vec<String>,
610}
611#[allow(dead_code)]
612impl PathBuf {
613    /// Creates a new empty path buffer.
614    pub fn new() -> Self {
615        Self {
616            components: Vec::new(),
617        }
618    }
619    /// Pushes a component.
620    pub fn push(&mut self, comp: impl Into<String>) {
621        self.components.push(comp.into());
622    }
623    /// Pops the last component.
624    pub fn pop(&mut self) {
625        self.components.pop();
626    }
627    /// Returns the current path as a `/`-separated string.
628    pub fn as_str(&self) -> String {
629        self.components.join("/")
630    }
631    /// Returns the depth of the path.
632    pub fn depth(&self) -> usize {
633        self.components.len()
634    }
635    /// Clears the path.
636    pub fn clear(&mut self) {
637        self.components.clear();
638    }
639}
640/// A type-erased function pointer with arity tracking.
641#[allow(dead_code)]
642pub struct RawFnPtr {
643    /// The raw function pointer (stored as usize for type erasure).
644    ptr: usize,
645    arity: usize,
646    name: String,
647}
648#[allow(dead_code)]
649impl RawFnPtr {
650    /// Creates a new raw function pointer descriptor.
651    pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
652        Self {
653            ptr,
654            arity,
655            name: name.into(),
656        }
657    }
658    /// Returns the arity.
659    pub fn arity(&self) -> usize {
660        self.arity
661    }
662    /// Returns the name.
663    pub fn name(&self) -> &str {
664        &self.name
665    }
666    /// Returns the raw pointer value.
667    pub fn raw(&self) -> usize {
668        self.ptr
669    }
670}
671/// A counter that can measure elapsed time between snapshots.
672#[allow(dead_code)]
673pub struct Stopwatch {
674    start: crate::wall_clock::Instant,
675    splits: Vec<f64>,
676}
677#[allow(dead_code)]
678impl Stopwatch {
679    /// Creates and starts a new stopwatch.
680    pub fn start() -> Self {
681        Self {
682            start: crate::wall_clock::Instant::now(),
683            splits: Vec::new(),
684        }
685    }
686    /// Records a split time (elapsed since start).
687    pub fn split(&mut self) {
688        self.splits.push(self.elapsed_ms());
689    }
690    /// Returns total elapsed milliseconds since start.
691    pub fn elapsed_ms(&self) -> f64 {
692        self.start.elapsed().as_secs_f64() * 1000.0
693    }
694    /// Returns all recorded split times.
695    pub fn splits(&self) -> &[f64] {
696        &self.splits
697    }
698    /// Returns the number of splits.
699    pub fn num_splits(&self) -> usize {
700        self.splits.len()
701    }
702}
703/// A simple decision tree node for rule dispatching.
704#[allow(dead_code)]
705#[allow(missing_docs)]
706pub enum DecisionNode {
707    /// A leaf with an action string.
708    Leaf(String),
709    /// An interior node: check `key` equals `val` → `yes_branch`, else `no_branch`.
710    Branch {
711        key: String,
712        val: String,
713        yes_branch: Box<DecisionNode>,
714        no_branch: Box<DecisionNode>,
715    },
716}
717#[allow(dead_code)]
718impl DecisionNode {
719    /// Evaluates the decision tree with the given context.
720    pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
721        match self {
722            DecisionNode::Leaf(action) => action.as_str(),
723            DecisionNode::Branch {
724                key,
725                val,
726                yes_branch,
727                no_branch,
728            } => {
729                let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
730                if actual == val.as_str() {
731                    yes_branch.evaluate(ctx)
732                } else {
733                    no_branch.evaluate(ctx)
734                }
735            }
736        }
737    }
738    /// Returns the depth of the decision tree.
739    pub fn depth(&self) -> usize {
740        match self {
741            DecisionNode::Leaf(_) => 0,
742            DecisionNode::Branch {
743                yes_branch,
744                no_branch,
745                ..
746            } => 1 + yes_branch.depth().max(no_branch.depth()),
747        }
748    }
749}
750/// A hierarchical configuration tree.
751#[allow(dead_code)]
752pub struct ConfigNode {
753    key: String,
754    value: Option<String>,
755    children: Vec<ConfigNode>,
756}
757#[allow(dead_code)]
758impl ConfigNode {
759    /// Creates a leaf config node with a value.
760    pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
761        Self {
762            key: key.into(),
763            value: Some(value.into()),
764            children: Vec::new(),
765        }
766    }
767    /// Creates a section node with children.
768    pub fn section(key: impl Into<String>) -> Self {
769        Self {
770            key: key.into(),
771            value: None,
772            children: Vec::new(),
773        }
774    }
775    /// Adds a child node.
776    pub fn add_child(&mut self, child: ConfigNode) {
777        self.children.push(child);
778    }
779    /// Returns the key.
780    pub fn key(&self) -> &str {
781        &self.key
782    }
783    /// Returns the value, or `None` for section nodes.
784    pub fn value(&self) -> Option<&str> {
785        self.value.as_deref()
786    }
787    /// Returns the number of children.
788    pub fn num_children(&self) -> usize {
789        self.children.len()
790    }
791    /// Looks up a dot-separated path.
792    pub fn lookup(&self, path: &str) -> Option<&str> {
793        let mut parts = path.splitn(2, '.');
794        let head = parts.next()?;
795        let tail = parts.next();
796        if head != self.key {
797            return None;
798        }
799        match tail {
800            None => self.value.as_deref(),
801            Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
802        }
803    }
804    fn lookup_relative(&self, path: &str) -> Option<&str> {
805        let mut parts = path.splitn(2, '.');
806        let head = parts.next()?;
807        let tail = parts.next();
808        if head != self.key {
809            return None;
810        }
811        match tail {
812            None => self.value.as_deref(),
813            Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
814        }
815    }
816}
817/// A versioned record that stores a history of values.
818#[allow(dead_code)]
819pub struct VersionedRecord<T: Clone> {
820    /// Every earlier value, oldest first: version `n` is `earlier[n]`.
821    earlier: Vec<T>,
822    /// The latest value (version `earlier.len()`), declared last so it drops last.
823    current: T,
824}
825#[allow(dead_code)]
826impl<T: Clone> VersionedRecord<T> {
827    /// Creates a new record with an initial value.
828    pub fn new(initial: T) -> Self {
829        Self {
830            earlier: Vec::new(),
831            current: initial,
832        }
833    }
834    /// Updates the record with a new version.
835    pub fn update(&mut self, val: T) {
836        let previous = std::mem::replace(&mut self.current, val);
837        self.earlier.push(previous);
838    }
839    /// Returns the current (latest) value.
840    pub fn current(&self) -> &T {
841        &self.current
842    }
843    /// Returns the value at version `n` (0-indexed), or `None`.
844    pub fn at_version(&self, n: usize) -> Option<&T> {
845        match self.earlier.get(n) {
846            Some(value) => Some(value),
847            None if n == self.earlier.len() => Some(&self.current),
848            None => None,
849        }
850    }
851    /// Returns the version number of the current value.
852    pub fn version(&self) -> usize {
853        self.earlier.len()
854    }
855    /// Returns `true` if more than one version exists.
856    pub fn has_history(&self) -> bool {
857        !self.earlier.is_empty()
858    }
859}
860/// A tagged union for representing a simple two-case discriminated union.
861#[allow(dead_code)]
862pub enum Either2<A, B> {
863    /// The first alternative.
864    First(A),
865    /// The second alternative.
866    Second(B),
867}
868#[allow(dead_code)]
869impl<A, B> Either2<A, B> {
870    /// Returns `true` if this is the first alternative.
871    pub fn is_first(&self) -> bool {
872        matches!(self, Either2::First(_))
873    }
874    /// Returns `true` if this is the second alternative.
875    pub fn is_second(&self) -> bool {
876        matches!(self, Either2::Second(_))
877    }
878    /// Returns the first value if present.
879    pub fn first(self) -> Option<A> {
880        match self {
881            Either2::First(a) => Some(a),
882            _ => None,
883        }
884    }
885    /// Returns the second value if present.
886    pub fn second(self) -> Option<B> {
887        match self {
888            Either2::Second(b) => Some(b),
889            _ => None,
890        }
891    }
892    /// Maps over the first alternative.
893    pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
894        match self {
895            Either2::First(a) => Either2::First(f(a)),
896            Either2::Second(b) => Either2::Second(b),
897        }
898    }
899}
900/// A mutable reference stack for tracking the current "focus" in a tree traversal.
901#[allow(dead_code)]
902pub struct FocusStack<T> {
903    items: Vec<T>,
904}
905#[allow(dead_code)]
906impl<T> FocusStack<T> {
907    /// Creates an empty focus stack.
908    pub fn new() -> Self {
909        Self { items: Vec::new() }
910    }
911    /// Focuses on `item`.
912    pub fn focus(&mut self, item: T) {
913        self.items.push(item);
914    }
915    /// Blurs (pops) the current focus.
916    pub fn blur(&mut self) -> Option<T> {
917        self.items.pop()
918    }
919    /// Returns the current focus, or `None`.
920    pub fn current(&self) -> Option<&T> {
921        self.items.last()
922    }
923    /// Returns the focus depth.
924    pub fn depth(&self) -> usize {
925        self.items.len()
926    }
927    /// Returns `true` if there is no current focus.
928    pub fn is_empty(&self) -> bool {
929        self.items.is_empty()
930    }
931}
932/// A trie-based prefix counter.
933#[allow(dead_code)]
934pub struct PrefixCounter {
935    children: std::collections::HashMap<char, PrefixCounter>,
936    count: usize,
937}
938#[allow(dead_code)]
939impl PrefixCounter {
940    /// Creates an empty prefix counter.
941    pub fn new() -> Self {
942        Self {
943            children: std::collections::HashMap::new(),
944            count: 0,
945        }
946    }
947    /// Records a string.
948    pub fn record(&mut self, s: &str) {
949        self.count += 1;
950        let mut node = self;
951        for c in s.chars() {
952            node = node.children.entry(c).or_default();
953            node.count += 1;
954        }
955    }
956    /// Returns how many strings have been recorded that start with `prefix`.
957    pub fn count_with_prefix(&self, prefix: &str) -> usize {
958        let mut node = self;
959        for c in prefix.chars() {
960            match node.children.get(&c) {
961                Some(n) => node = n,
962                None => return 0,
963            }
964        }
965        node.count
966    }
967}
968/// A fixed-size sliding window that computes a running sum.
969#[allow(dead_code)]
970pub struct SlidingSum {
971    window: Vec<f64>,
972    capacity: usize,
973    pos: usize,
974    sum: f64,
975    count: usize,
976}
977#[allow(dead_code)]
978impl SlidingSum {
979    /// Creates a sliding sum with the given window size.
980    pub fn new(capacity: usize) -> Self {
981        Self {
982            window: vec![0.0; capacity],
983            capacity,
984            pos: 0,
985            sum: 0.0,
986            count: 0,
987        }
988    }
989    /// Adds a value to the window, removing the oldest if full.
990    pub fn push(&mut self, val: f64) {
991        let oldest = self.window[self.pos];
992        self.sum -= oldest;
993        self.sum += val;
994        self.window[self.pos] = val;
995        self.pos = (self.pos + 1) % self.capacity;
996        if self.count < self.capacity {
997            self.count += 1;
998        }
999    }
1000    /// Returns the current window sum.
1001    pub fn sum(&self) -> f64 {
1002        self.sum
1003    }
1004    /// Returns the window mean, or `None` if empty.
1005    pub fn mean(&self) -> Option<f64> {
1006        if self.count == 0 {
1007            None
1008        } else {
1009            Some(self.sum / self.count as f64)
1010        }
1011    }
1012    /// Returns the current window size (number of valid elements).
1013    pub fn count(&self) -> usize {
1014        self.count
1015    }
1016}
1017/// A simple stack-based calculator for arithmetic expressions.
1018#[allow(dead_code)]
1019pub struct StackCalc {
1020    stack: Vec<i64>,
1021}
1022#[allow(dead_code)]
1023impl StackCalc {
1024    /// Creates a new empty calculator.
1025    pub fn new() -> Self {
1026        Self { stack: Vec::new() }
1027    }
1028    /// Pushes an integer literal.
1029    pub fn push(&mut self, n: i64) {
1030        self.stack.push(n);
1031    }
1032    /// Replaces the top two values, `b` on top of `a`, with `op(a, b)` and
1033    /// returns it.  Returns `None`, leaving the stack unchanged, if it holds
1034    /// fewer than two values.
1035    fn apply_binary(&mut self, op: impl FnOnce(i64, i64) -> i64) -> Option<i64> {
1036        let (rest_len, a, b) = match self.stack[..] {
1037            [ref rest @ .., a, b] => (rest.len(), a, b),
1038            _ => return None,
1039        };
1040        let value = op(a, b);
1041        self.stack.truncate(rest_len);
1042        self.stack.push(value);
1043        Some(value)
1044    }
1045    /// Adds the top two values and returns the sum, which replaces them.
1046    /// Returns `None`, leaving the stack unchanged, if it holds fewer than
1047    /// two values.
1048    pub fn add(&mut self) -> Option<i64> {
1049        self.apply_binary(|a, b| a + b)
1050    }
1051    /// Subtracts top from second and returns the difference, which replaces
1052    /// them.  Returns `None`, leaving the stack unchanged, if it holds fewer
1053    /// than two values.
1054    pub fn sub(&mut self) -> Option<i64> {
1055        self.apply_binary(|a, b| a - b)
1056    }
1057    /// Multiplies the top two values and returns the product, which replaces
1058    /// them.  Returns `None`, leaving the stack unchanged, if it holds fewer
1059    /// than two values.
1060    pub fn mul(&mut self) -> Option<i64> {
1061        self.apply_binary(|a, b| a * b)
1062    }
1063    /// Peeks the top value.
1064    pub fn peek(&self) -> Option<i64> {
1065        self.stack.last().copied()
1066    }
1067    /// Returns the stack depth.
1068    pub fn depth(&self) -> usize {
1069        self.stack.len()
1070    }
1071}
1072/// A simple directed acyclic graph.
1073#[allow(dead_code)]
1074pub struct SimpleDag {
1075    /// `edges[i]` is the list of direct successors of node `i`.
1076    edges: Vec<Vec<usize>>,
1077}
1078#[allow(dead_code)]
1079impl SimpleDag {
1080    /// Creates a DAG with `n` nodes and no edges.
1081    pub fn new(n: usize) -> Self {
1082        Self {
1083            edges: vec![Vec::new(); n],
1084        }
1085    }
1086    /// Adds an edge from `from` to `to`.
1087    pub fn add_edge(&mut self, from: usize, to: usize) {
1088        if from < self.edges.len() {
1089            self.edges[from].push(to);
1090        }
1091    }
1092    /// Returns the successors of `node`.
1093    pub fn successors(&self, node: usize) -> &[usize] {
1094        self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
1095    }
1096    /// Returns `true` if `from` can reach `to` via DFS.
1097    pub fn can_reach(&self, from: usize, to: usize) -> bool {
1098        let mut visited = vec![false; self.edges.len()];
1099        self.dfs(from, to, &mut visited)
1100    }
1101    fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
1102        if cur == target {
1103            return true;
1104        }
1105        if cur >= visited.len() || visited[cur] {
1106            return false;
1107        }
1108        visited[cur] = true;
1109        for &next in self.successors(cur) {
1110            if self.dfs(next, target, visited) {
1111                return true;
1112            }
1113        }
1114        false
1115    }
1116    /// Returns the topological order of nodes, or `None` if a cycle is detected.
1117    pub fn topological_sort(&self) -> Option<Vec<usize>> {
1118        let n = self.edges.len();
1119        let mut in_degree = vec![0usize; n];
1120        for succs in &self.edges {
1121            for &s in succs {
1122                if s < n {
1123                    in_degree[s] += 1;
1124                }
1125            }
1126        }
1127        let mut queue: std::collections::VecDeque<usize> =
1128            (0..n).filter(|&i| in_degree[i] == 0).collect();
1129        let mut order = Vec::new();
1130        while let Some(node) = queue.pop_front() {
1131            order.push(node);
1132            for &s in self.successors(node) {
1133                if s < n {
1134                    in_degree[s] -= 1;
1135                    if in_degree[s] == 0 {
1136                        queue.push_back(s);
1137                    }
1138                }
1139            }
1140        }
1141        if order.len() == n {
1142            Some(order)
1143        } else {
1144            None
1145        }
1146    }
1147    /// Returns the number of nodes.
1148    pub fn num_nodes(&self) -> usize {
1149        self.edges.len()
1150    }
1151}
1152/// A write-once cell.
1153#[allow(dead_code)]
1154pub struct WriteOnce<T> {
1155    value: std::cell::Cell<Option<T>>,
1156}
1157#[allow(dead_code)]
1158impl<T: Copy> WriteOnce<T> {
1159    /// Creates an empty write-once cell.
1160    pub fn new() -> Self {
1161        Self {
1162            value: std::cell::Cell::new(None),
1163        }
1164    }
1165    /// Writes a value.  Returns `false` if already written.
1166    pub fn write(&self, val: T) -> bool {
1167        if self.value.get().is_some() {
1168            return false;
1169        }
1170        self.value.set(Some(val));
1171        true
1172    }
1173    /// Returns the value if written.
1174    pub fn read(&self) -> Option<T> {
1175        self.value.get()
1176    }
1177    /// Returns `true` if the value has been written.
1178    pub fn is_written(&self) -> bool {
1179        self.value.get().is_some()
1180    }
1181}
1182/// A named substitution map: maps `Name → Expr`.
1183#[derive(Clone, Debug, Default)]
1184pub struct NamedSubst {
1185    map: std::collections::HashMap<Name, Expr>,
1186}
1187impl NamedSubst {
1188    /// Create an empty substitution.
1189    pub fn new() -> Self {
1190        Self::default()
1191    }
1192    /// Insert a binding.
1193    pub fn insert(&mut self, name: Name, val: Expr) {
1194        self.map.insert(name, val);
1195    }
1196    /// Look up a name.
1197    pub fn get(&self, name: &Name) -> Option<&Expr> {
1198        self.map.get(name)
1199    }
1200    /// Return the number of bindings.
1201    pub fn len(&self) -> usize {
1202        self.map.len()
1203    }
1204    /// Check if empty.
1205    pub fn is_empty(&self) -> bool {
1206        self.map.is_empty()
1207    }
1208    /// Apply the substitution to an expression.
1209    ///
1210    /// Replaces any `Const(name, [])` that appears in the map.
1211    pub fn apply(&self, expr: &Expr) -> Expr {
1212        named_subst_apply(expr, self)
1213    }
1214}
1215/// A pair of `StatSummary` values tracking before/after a transformation.
1216#[allow(dead_code)]
1217pub struct TransformStat {
1218    before: StatSummary,
1219    after: StatSummary,
1220}
1221#[allow(dead_code)]
1222impl TransformStat {
1223    /// Creates a new transform stat recorder.
1224    pub fn new() -> Self {
1225        Self {
1226            before: StatSummary::new(),
1227            after: StatSummary::new(),
1228        }
1229    }
1230    /// Records a before value.
1231    pub fn record_before(&mut self, v: f64) {
1232        self.before.record(v);
1233    }
1234    /// Records an after value.
1235    pub fn record_after(&mut self, v: f64) {
1236        self.after.record(v);
1237    }
1238    /// Returns the mean reduction ratio (after/before).
1239    pub fn mean_ratio(&self) -> Option<f64> {
1240        let b = self.before.mean()?;
1241        let a = self.after.mean()?;
1242        if b.abs() < f64::EPSILON {
1243            return None;
1244        }
1245        Some(a / b)
1246    }
1247}
1248/// A token bucket rate limiter.
1249#[allow(dead_code)]
1250pub struct TokenBucket {
1251    capacity: u64,
1252    tokens: u64,
1253    refill_per_ms: u64,
1254    last_refill: crate::wall_clock::Instant,
1255}
1256#[allow(dead_code)]
1257impl TokenBucket {
1258    /// Creates a new token bucket.
1259    pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
1260        Self {
1261            capacity,
1262            tokens: capacity,
1263            refill_per_ms,
1264            last_refill: crate::wall_clock::Instant::now(),
1265        }
1266    }
1267    /// Attempts to consume `n` tokens.  Returns `true` on success.
1268    pub fn try_consume(&mut self, n: u64) -> bool {
1269        self.refill();
1270        if self.tokens >= n {
1271            self.tokens -= n;
1272            true
1273        } else {
1274            false
1275        }
1276    }
1277    fn refill(&mut self) {
1278        let now = crate::wall_clock::Instant::now();
1279        let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
1280        if elapsed_ms > 0 {
1281            let new_tokens = elapsed_ms * self.refill_per_ms;
1282            self.tokens = (self.tokens + new_tokens).min(self.capacity);
1283            self.last_refill = now;
1284        }
1285    }
1286    /// Returns the number of currently available tokens.
1287    pub fn available(&self) -> u64 {
1288        self.tokens
1289    }
1290    /// Returns the bucket capacity.
1291    pub fn capacity(&self) -> u64 {
1292        self.capacity
1293    }
1294}