Skip to main content

oxilean_kernel/expr_util/
types.rs

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