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: crate::wall_clock::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: crate::wall_clock::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: crate::wall_clock::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: crate::wall_clock::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 = crate::wall_clock::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    /// Every earlier value, oldest first: version `n` is `earlier[n]`.
509    earlier: Vec<T>,
510    /// The latest value (version `earlier.len()`), declared last so it drops last.
511    current: T,
512}
513#[allow(dead_code)]
514impl<T: Clone> VersionedRecord<T> {
515    /// Creates a new record with an initial value.
516    pub fn new(initial: T) -> Self {
517        Self {
518            earlier: Vec::new(),
519            current: initial,
520        }
521    }
522    /// Updates the record with a new version.
523    pub fn update(&mut self, val: T) {
524        let previous = std::mem::replace(&mut self.current, val);
525        self.earlier.push(previous);
526    }
527    /// Returns the current (latest) value.
528    pub fn current(&self) -> &T {
529        &self.current
530    }
531    /// Returns the value at version `n` (0-indexed), or `None`.
532    pub fn at_version(&self, n: usize) -> Option<&T> {
533        match self.earlier.get(n) {
534            Some(value) => Some(value),
535            None if n == self.earlier.len() => Some(&self.current),
536            None => None,
537        }
538    }
539    /// Returns the version number of the current value.
540    pub fn version(&self) -> usize {
541        self.earlier.len()
542    }
543    /// Returns `true` if more than one version exists.
544    pub fn has_history(&self) -> bool {
545        !self.earlier.is_empty()
546    }
547}
548/// A fixed-size sliding window that computes a running sum.
549#[allow(dead_code)]
550pub struct SlidingSum {
551    window: Vec<f64>,
552    capacity: usize,
553    pos: usize,
554    sum: f64,
555    count: usize,
556}
557#[allow(dead_code)]
558impl SlidingSum {
559    /// Creates a sliding sum with the given window size.
560    pub fn new(capacity: usize) -> Self {
561        Self {
562            window: vec![0.0; capacity],
563            capacity,
564            pos: 0,
565            sum: 0.0,
566            count: 0,
567        }
568    }
569    /// Adds a value to the window, removing the oldest if full.
570    pub fn push(&mut self, val: f64) {
571        let oldest = self.window[self.pos];
572        self.sum -= oldest;
573        self.sum += val;
574        self.window[self.pos] = val;
575        self.pos = (self.pos + 1) % self.capacity;
576        if self.count < self.capacity {
577            self.count += 1;
578        }
579    }
580    /// Returns the current window sum.
581    pub fn sum(&self) -> f64 {
582        self.sum
583    }
584    /// Returns the window mean, or `None` if empty.
585    pub fn mean(&self) -> Option<f64> {
586        if self.count == 0 {
587            None
588        } else {
589            Some(self.sum / self.count as f64)
590        }
591    }
592    /// Returns the current window size (number of valid elements).
593    pub fn count(&self) -> usize {
594        self.count
595    }
596}
597/// A min-heap implemented as a binary heap.
598#[allow(dead_code)]
599pub struct MinHeap<T: Ord> {
600    data: Vec<T>,
601}
602#[allow(dead_code)]
603impl<T: Ord> MinHeap<T> {
604    /// Creates a new empty min-heap.
605    pub fn new() -> Self {
606        Self { data: Vec::new() }
607    }
608    /// Inserts an element.
609    pub fn push(&mut self, val: T) {
610        self.data.push(val);
611        self.sift_up(self.data.len() - 1);
612    }
613    /// Removes and returns the minimum element.
614    pub fn pop(&mut self) -> Option<T> {
615        if self.data.is_empty() {
616            return None;
617        }
618        let n = self.data.len();
619        self.data.swap(0, n - 1);
620        let min = self.data.pop();
621        if !self.data.is_empty() {
622            self.sift_down(0);
623        }
624        min
625    }
626    /// Returns a reference to the minimum element.
627    pub fn peek(&self) -> Option<&T> {
628        self.data.first()
629    }
630    /// Returns the number of elements.
631    pub fn len(&self) -> usize {
632        self.data.len()
633    }
634    /// Returns `true` if empty.
635    pub fn is_empty(&self) -> bool {
636        self.data.is_empty()
637    }
638    fn sift_up(&mut self, mut i: usize) {
639        while i > 0 {
640            let parent = (i - 1) / 2;
641            if self.data[i] < self.data[parent] {
642                self.data.swap(i, parent);
643                i = parent;
644            } else {
645                break;
646            }
647        }
648    }
649    fn sift_down(&mut self, mut i: usize) {
650        let n = self.data.len();
651        loop {
652            let left = 2 * i + 1;
653            let right = 2 * i + 2;
654            let mut smallest = i;
655            if left < n && self.data[left] < self.data[smallest] {
656                smallest = left;
657            }
658            if right < n && self.data[right] < self.data[smallest] {
659                smallest = right;
660            }
661            if smallest == i {
662                break;
663            }
664            self.data.swap(i, smallest);
665            i = smallest;
666        }
667    }
668}
669/// A counter for tracking how many items are in each of `N` buckets.
670#[allow(dead_code)]
671pub struct BucketCounter<const N: usize> {
672    buckets: [u64; N],
673}
674#[allow(dead_code)]
675impl<const N: usize> BucketCounter<N> {
676    /// Creates a zeroed bucket counter.
677    pub const fn new() -> Self {
678        Self { buckets: [0u64; N] }
679    }
680    /// Increments bucket `i`.
681    pub fn inc(&mut self, i: usize) {
682        if i < N {
683            self.buckets[i] += 1;
684        }
685    }
686    /// Returns the count for bucket `i`.
687    pub fn get(&self, i: usize) -> u64 {
688        if i < N {
689            self.buckets[i]
690        } else {
691            0
692        }
693    }
694    /// Returns the total count across all buckets.
695    pub fn total(&self) -> u64 {
696        self.buckets.iter().sum()
697    }
698    /// Returns the index of the bucket with the highest count.
699    pub fn argmax(&self) -> usize {
700        self.buckets
701            .iter()
702            .enumerate()
703            .max_by_key(|(_, &v)| v)
704            .map(|(i, _)| i)
705            .unwrap_or(0)
706    }
707}
708/// A label set for a graph node.
709#[allow(dead_code)]
710pub struct LabelSet {
711    labels: Vec<String>,
712}
713#[allow(dead_code)]
714impl LabelSet {
715    /// Creates a new empty label set.
716    pub fn new() -> Self {
717        Self { labels: Vec::new() }
718    }
719    /// Adds a label (deduplicates).
720    pub fn add(&mut self, label: impl Into<String>) {
721        let s = label.into();
722        if !self.labels.contains(&s) {
723            self.labels.push(s);
724        }
725    }
726    /// Returns `true` if `label` is present.
727    pub fn has(&self, label: &str) -> bool {
728        self.labels.iter().any(|l| l == label)
729    }
730    /// Returns the count of labels.
731    pub fn count(&self) -> usize {
732        self.labels.len()
733    }
734    /// Returns all labels.
735    pub fn all(&self) -> &[String] {
736        &self.labels
737    }
738}
739/// A mutable reference stack for tracking the current "focus" in a tree traversal.
740#[allow(dead_code)]
741pub struct FocusStack<T> {
742    items: Vec<T>,
743}
744#[allow(dead_code)]
745impl<T> FocusStack<T> {
746    /// Creates an empty focus stack.
747    pub fn new() -> Self {
748        Self { items: Vec::new() }
749    }
750    /// Focuses on `item`.
751    pub fn focus(&mut self, item: T) {
752        self.items.push(item);
753    }
754    /// Blurs (pops) the current focus.
755    pub fn blur(&mut self) -> Option<T> {
756        self.items.pop()
757    }
758    /// Returns the current focus, or `None`.
759    pub fn current(&self) -> Option<&T> {
760        self.items.last()
761    }
762    /// Returns the focus depth.
763    pub fn depth(&self) -> usize {
764        self.items.len()
765    }
766    /// Returns `true` if there is no current focus.
767    pub fn is_empty(&self) -> bool {
768        self.items.is_empty()
769    }
770}
771/// A simple key-value store backed by a sorted Vec for small maps.
772#[allow(dead_code)]
773pub struct SmallMap<K: Ord + Clone, V: Clone> {
774    entries: Vec<(K, V)>,
775}
776#[allow(dead_code)]
777impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
778    /// Creates a new empty small map.
779    pub fn new() -> Self {
780        Self {
781            entries: Vec::new(),
782        }
783    }
784    /// Inserts or replaces the value for `key`.
785    pub fn insert(&mut self, key: K, val: V) {
786        match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
787            Ok(i) => self.entries[i].1 = val,
788            Err(i) => self.entries.insert(i, (key, val)),
789        }
790    }
791    /// Returns the value for `key`, or `None`.
792    pub fn get(&self, key: &K) -> Option<&V> {
793        self.entries
794            .binary_search_by_key(&key, |(k, _)| k)
795            .ok()
796            .map(|i| &self.entries[i].1)
797    }
798    /// Returns the number of entries.
799    pub fn len(&self) -> usize {
800        self.entries.len()
801    }
802    /// Returns `true` if empty.
803    pub fn is_empty(&self) -> bool {
804        self.entries.is_empty()
805    }
806    /// Returns all keys.
807    pub fn keys(&self) -> Vec<&K> {
808        self.entries.iter().map(|(k, _)| k).collect()
809    }
810    /// Returns all values.
811    pub fn values(&self) -> Vec<&V> {
812        self.entries.iter().map(|(_, v)| v).collect()
813    }
814}
815/// A window iterator that yields overlapping windows of size `n`.
816#[allow(dead_code)]
817pub struct WindowIterator<'a, T> {
818    pub(super) data: &'a [T],
819    pub(super) pos: usize,
820    pub(super) window: usize,
821}
822#[allow(dead_code)]
823impl<'a, T> WindowIterator<'a, T> {
824    /// Creates a new window iterator.
825    pub fn new(data: &'a [T], window: usize) -> Self {
826        Self {
827            data,
828            pos: 0,
829            window,
830        }
831    }
832}
833/// A simple decision tree node for rule dispatching.
834#[allow(dead_code)]
835#[allow(missing_docs)]
836pub enum DecisionNode {
837    /// A leaf with an action string.
838    Leaf(String),
839    /// An interior node: check `key` equals `val` → `yes_branch`, else `no_branch`.
840    Branch {
841        key: String,
842        val: String,
843        yes_branch: Box<DecisionNode>,
844        no_branch: Box<DecisionNode>,
845    },
846}
847#[allow(dead_code)]
848impl DecisionNode {
849    /// Evaluates the decision tree with the given context.
850    pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
851        match self {
852            DecisionNode::Leaf(action) => action.as_str(),
853            DecisionNode::Branch {
854                key,
855                val,
856                yes_branch,
857                no_branch,
858            } => {
859                let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
860                if actual == val.as_str() {
861                    yes_branch.evaluate(ctx)
862                } else {
863                    no_branch.evaluate(ctx)
864                }
865            }
866        }
867    }
868    /// Returns the depth of the decision tree.
869    pub fn depth(&self) -> usize {
870        match self {
871            DecisionNode::Leaf(_) => 0,
872            DecisionNode::Branch {
873                yes_branch,
874                no_branch,
875                ..
876            } => 1 + yes_branch.depth().max(no_branch.depth()),
877        }
878    }
879}
880/// A type-erased function pointer with arity tracking.
881#[allow(dead_code)]
882pub struct RawFnPtr {
883    /// The raw function pointer (stored as usize for type erasure).
884    ptr: usize,
885    arity: usize,
886    name: String,
887}
888#[allow(dead_code)]
889impl RawFnPtr {
890    /// Creates a new raw function pointer descriptor.
891    pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
892        Self {
893            ptr,
894            arity,
895            name: name.into(),
896        }
897    }
898    /// Returns the arity.
899    pub fn arity(&self) -> usize {
900        self.arity
901    }
902    /// Returns the name.
903    pub fn name(&self) -> &str {
904        &self.name
905    }
906    /// Returns the raw pointer value.
907    pub fn raw(&self) -> usize {
908        self.ptr
909    }
910}
911/// A write-once cell.
912#[allow(dead_code)]
913pub struct WriteOnce<T> {
914    value: std::cell::Cell<Option<T>>,
915}
916#[allow(dead_code)]
917impl<T: Copy> WriteOnce<T> {
918    /// Creates an empty write-once cell.
919    pub fn new() -> Self {
920        Self {
921            value: std::cell::Cell::new(None),
922        }
923    }
924    /// Writes a value.  Returns `false` if already written.
925    pub fn write(&self, val: T) -> bool {
926        if self.value.get().is_some() {
927            return false;
928        }
929        self.value.set(Some(val));
930        true
931    }
932    /// Returns the value if written.
933    pub fn read(&self) -> Option<T> {
934        self.value.get()
935    }
936    /// Returns `true` if the value has been written.
937    pub fn is_written(&self) -> bool {
938        self.value.get().is_some()
939    }
940}
941/// A sparse vector: stores only non-default elements.
942#[allow(dead_code)]
943pub struct SparseVec<T: Default + Clone + PartialEq> {
944    entries: std::collections::HashMap<usize, T>,
945    default_: T,
946    logical_len: usize,
947}
948#[allow(dead_code)]
949impl<T: Default + Clone + PartialEq> SparseVec<T> {
950    /// Creates a new sparse vector with logical length `len`.
951    pub fn new(len: usize) -> Self {
952        Self {
953            entries: std::collections::HashMap::new(),
954            default_: T::default(),
955            logical_len: len,
956        }
957    }
958    /// Sets element at `idx`.
959    pub fn set(&mut self, idx: usize, val: T) {
960        if val == self.default_ {
961            self.entries.remove(&idx);
962        } else {
963            self.entries.insert(idx, val);
964        }
965    }
966    /// Gets element at `idx`.
967    pub fn get(&self, idx: usize) -> &T {
968        self.entries.get(&idx).unwrap_or(&self.default_)
969    }
970    /// Returns the logical length.
971    pub fn len(&self) -> usize {
972        self.logical_len
973    }
974    /// Returns whether the collection is empty.
975    pub fn is_empty(&self) -> bool {
976        self.len() == 0
977    }
978    /// Returns the number of non-default elements.
979    pub fn nnz(&self) -> usize {
980        self.entries.len()
981    }
982}
983/// A simple stack-based calculator for arithmetic expressions.
984#[allow(dead_code)]
985pub struct StackCalc {
986    stack: Vec<i64>,
987}
988#[allow(dead_code)]
989impl StackCalc {
990    /// Creates a new empty calculator.
991    pub fn new() -> Self {
992        Self { stack: Vec::new() }
993    }
994    /// Pushes an integer literal.
995    pub fn push(&mut self, n: i64) {
996        self.stack.push(n);
997    }
998    /// Replaces the top two values, `b` on top of `a`, with `op(a, b)` and
999    /// returns it.  Returns `None`, leaving the stack unchanged, if it holds
1000    /// fewer than two values.
1001    fn apply_binary(&mut self, op: impl FnOnce(i64, i64) -> i64) -> Option<i64> {
1002        let (rest_len, a, b) = match self.stack[..] {
1003            [ref rest @ .., a, b] => (rest.len(), a, b),
1004            _ => return None,
1005        };
1006        let value = op(a, b);
1007        self.stack.truncate(rest_len);
1008        self.stack.push(value);
1009        Some(value)
1010    }
1011    /// Adds the top two values and returns the sum, which replaces them.
1012    /// Returns `None`, leaving the stack unchanged, if it holds fewer than
1013    /// two values.
1014    pub fn add(&mut self) -> Option<i64> {
1015        self.apply_binary(|a, b| a + b)
1016    }
1017    /// Subtracts top from second and returns the difference, which replaces
1018    /// them.  Returns `None`, leaving the stack unchanged, if it holds fewer
1019    /// than two values.
1020    pub fn sub(&mut self) -> Option<i64> {
1021        self.apply_binary(|a, b| a - b)
1022    }
1023    /// Multiplies the top two values and returns the product, which replaces
1024    /// them.  Returns `None`, leaving the stack unchanged, if it holds fewer
1025    /// than two values.
1026    pub fn mul(&mut self) -> Option<i64> {
1027        self.apply_binary(|a, b| a * b)
1028    }
1029    /// Peeks the top value.
1030    pub fn peek(&self) -> Option<i64> {
1031        self.stack.last().copied()
1032    }
1033    /// Returns the stack depth.
1034    pub fn depth(&self) -> usize {
1035        self.stack.len()
1036    }
1037}
1038/// A dependency closure builder (transitive closure via BFS).
1039#[allow(dead_code)]
1040pub struct TransitiveClosure {
1041    adj: Vec<Vec<usize>>,
1042    n: usize,
1043}
1044#[allow(dead_code)]
1045impl TransitiveClosure {
1046    /// Creates a transitive closure builder for `n` nodes.
1047    pub fn new(n: usize) -> Self {
1048        Self {
1049            adj: vec![Vec::new(); n],
1050            n,
1051        }
1052    }
1053    /// Adds a direct edge.
1054    pub fn add_edge(&mut self, from: usize, to: usize) {
1055        if from < self.n {
1056            self.adj[from].push(to);
1057        }
1058    }
1059    /// Computes all nodes reachable from `start` (including `start`).
1060    pub fn reachable_from(&self, start: usize) -> Vec<usize> {
1061        let mut visited = vec![false; self.n];
1062        let mut queue = std::collections::VecDeque::new();
1063        queue.push_back(start);
1064        while let Some(node) = queue.pop_front() {
1065            if node >= self.n || visited[node] {
1066                continue;
1067            }
1068            visited[node] = true;
1069            for &next in &self.adj[node] {
1070                queue.push_back(next);
1071            }
1072        }
1073        (0..self.n).filter(|&i| visited[i]).collect()
1074    }
1075    /// Returns `true` if `from` can transitively reach `to`.
1076    pub fn can_reach(&self, from: usize, to: usize) -> bool {
1077        self.reachable_from(from).contains(&to)
1078    }
1079}
1080/// A simple directed acyclic graph.
1081#[allow(dead_code)]
1082pub struct SimpleDag {
1083    /// `edges[i]` is the list of direct successors of node `i`.
1084    edges: Vec<Vec<usize>>,
1085}
1086#[allow(dead_code)]
1087impl SimpleDag {
1088    /// Creates a DAG with `n` nodes and no edges.
1089    pub fn new(n: usize) -> Self {
1090        Self {
1091            edges: vec![Vec::new(); n],
1092        }
1093    }
1094    /// Adds an edge from `from` to `to`.
1095    pub fn add_edge(&mut self, from: usize, to: usize) {
1096        if from < self.edges.len() {
1097            self.edges[from].push(to);
1098        }
1099    }
1100    /// Returns the successors of `node`.
1101    pub fn successors(&self, node: usize) -> &[usize] {
1102        self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
1103    }
1104    /// Returns `true` if `from` can reach `to` via DFS.
1105    pub fn can_reach(&self, from: usize, to: usize) -> bool {
1106        let mut visited = vec![false; self.edges.len()];
1107        self.dfs(from, to, &mut visited)
1108    }
1109    fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
1110        if cur == target {
1111            return true;
1112        }
1113        if cur >= visited.len() || visited[cur] {
1114            return false;
1115        }
1116        visited[cur] = true;
1117        for &next in self.successors(cur) {
1118            if self.dfs(next, target, visited) {
1119                return true;
1120            }
1121        }
1122        false
1123    }
1124    /// Returns the topological order of nodes, or `None` if a cycle is detected.
1125    pub fn topological_sort(&self) -> Option<Vec<usize>> {
1126        let n = self.edges.len();
1127        let mut in_degree = vec![0usize; n];
1128        for succs in &self.edges {
1129            for &s in succs {
1130                if s < n {
1131                    in_degree[s] += 1;
1132                }
1133            }
1134        }
1135        let mut queue: std::collections::VecDeque<usize> =
1136            (0..n).filter(|&i| in_degree[i] == 0).collect();
1137        let mut order = Vec::new();
1138        while let Some(node) = queue.pop_front() {
1139            order.push(node);
1140            for &s in self.successors(node) {
1141                if s < n {
1142                    in_degree[s] -= 1;
1143                    if in_degree[s] == 0 {
1144                        queue.push_back(s);
1145                    }
1146                }
1147            }
1148        }
1149        if order.len() == n {
1150            Some(order)
1151        } else {
1152            None
1153        }
1154    }
1155    /// Returns the number of nodes.
1156    pub fn num_nodes(&self) -> usize {
1157        self.edges.len()
1158    }
1159}
1160/// A hierarchical configuration tree.
1161#[allow(dead_code)]
1162pub struct ConfigNode {
1163    key: String,
1164    value: Option<String>,
1165    children: Vec<ConfigNode>,
1166}
1167#[allow(dead_code)]
1168impl ConfigNode {
1169    /// Creates a leaf config node with a value.
1170    pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
1171        Self {
1172            key: key.into(),
1173            value: Some(value.into()),
1174            children: Vec::new(),
1175        }
1176    }
1177    /// Creates a section node with children.
1178    pub fn section(key: impl Into<String>) -> Self {
1179        Self {
1180            key: key.into(),
1181            value: None,
1182            children: Vec::new(),
1183        }
1184    }
1185    /// Adds a child node.
1186    pub fn add_child(&mut self, child: ConfigNode) {
1187        self.children.push(child);
1188    }
1189    /// Returns the key.
1190    pub fn key(&self) -> &str {
1191        &self.key
1192    }
1193    /// Returns the value, or `None` for section nodes.
1194    pub fn value(&self) -> Option<&str> {
1195        self.value.as_deref()
1196    }
1197    /// Returns the number of children.
1198    pub fn num_children(&self) -> usize {
1199        self.children.len()
1200    }
1201    /// Looks up a dot-separated path.
1202    pub fn lookup(&self, path: &str) -> Option<&str> {
1203        let mut parts = path.splitn(2, '.');
1204        let head = parts.next()?;
1205        let tail = parts.next();
1206        if head != self.key {
1207            return None;
1208        }
1209        match tail {
1210            None => self.value.as_deref(),
1211            Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1212        }
1213    }
1214    fn lookup_relative(&self, path: &str) -> Option<&str> {
1215        let mut parts = path.splitn(2, '.');
1216        let head = parts.next()?;
1217        let tail = parts.next();
1218        if head != self.key {
1219            return None;
1220        }
1221        match tail {
1222            None => self.value.as_deref(),
1223            Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1224        }
1225    }
1226}
1227/// A generic counter that tracks min/max/sum for statistical summaries.
1228#[allow(dead_code)]
1229pub struct StatSummary {
1230    count: u64,
1231    sum: f64,
1232    min: f64,
1233    max: f64,
1234}
1235#[allow(dead_code)]
1236impl StatSummary {
1237    /// Creates an empty summary.
1238    pub fn new() -> Self {
1239        Self {
1240            count: 0,
1241            sum: 0.0,
1242            min: f64::INFINITY,
1243            max: f64::NEG_INFINITY,
1244        }
1245    }
1246    /// Records a sample.
1247    pub fn record(&mut self, val: f64) {
1248        self.count += 1;
1249        self.sum += val;
1250        if val < self.min {
1251            self.min = val;
1252        }
1253        if val > self.max {
1254            self.max = val;
1255        }
1256    }
1257    /// Returns the mean, or `None` if no samples.
1258    pub fn mean(&self) -> Option<f64> {
1259        if self.count == 0 {
1260            None
1261        } else {
1262            Some(self.sum / self.count as f64)
1263        }
1264    }
1265    /// Returns the minimum, or `None` if no samples.
1266    pub fn min(&self) -> Option<f64> {
1267        if self.count == 0 {
1268            None
1269        } else {
1270            Some(self.min)
1271        }
1272    }
1273    /// Returns the maximum, or `None` if no samples.
1274    pub fn max(&self) -> Option<f64> {
1275        if self.count == 0 {
1276            None
1277        } else {
1278            Some(self.max)
1279        }
1280    }
1281    /// Returns the count of recorded samples.
1282    pub fn count(&self) -> u64 {
1283        self.count
1284    }
1285}
1286/// A simple mutable key-value store for test fixtures.
1287#[allow(dead_code)]
1288pub struct Fixture {
1289    data: std::collections::HashMap<String, String>,
1290}
1291#[allow(dead_code)]
1292impl Fixture {
1293    /// Creates an empty fixture.
1294    pub fn new() -> Self {
1295        Self {
1296            data: std::collections::HashMap::new(),
1297        }
1298    }
1299    /// Sets a key.
1300    pub fn set(&mut self, key: impl Into<String>, val: impl Into<String>) {
1301        self.data.insert(key.into(), val.into());
1302    }
1303    /// Gets a value.
1304    pub fn get(&self, key: &str) -> Option<&str> {
1305        self.data.get(key).map(|s| s.as_str())
1306    }
1307    /// Returns the number of entries.
1308    pub fn len(&self) -> usize {
1309        self.data.len()
1310    }
1311    /// Returns whether the collection is empty.
1312    pub fn is_empty(&self) -> bool {
1313        self.len() == 0
1314    }
1315}