Skip to main content

oxilean_kernel/substitution/
types.rs

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