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: std::time::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: std::time::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: std::time::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: std::time::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 = std::time::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    /// Adds the top two values.  Panics if fewer than two values.
561    pub fn add(&mut self) {
562        let b = self
563            .stack
564            .pop()
565            .expect("stack must have at least two values for add");
566        let a = self
567            .stack
568            .pop()
569            .expect("stack must have at least two values for add");
570        self.stack.push(a + b);
571    }
572    /// Subtracts top from second.
573    pub fn sub(&mut self) {
574        let b = self
575            .stack
576            .pop()
577            .expect("stack must have at least two values for sub");
578        let a = self
579            .stack
580            .pop()
581            .expect("stack must have at least two values for sub");
582        self.stack.push(a - b);
583    }
584    /// Multiplies the top two values.
585    pub fn mul(&mut self) {
586        let b = self
587            .stack
588            .pop()
589            .expect("stack must have at least two values for mul");
590        let a = self
591            .stack
592            .pop()
593            .expect("stack must have at least two values for mul");
594        self.stack.push(a * b);
595    }
596    /// Peeks the top value.
597    pub fn peek(&self) -> Option<i64> {
598        self.stack.last().copied()
599    }
600    /// Returns the stack depth.
601    pub fn depth(&self) -> usize {
602        self.stack.len()
603    }
604}
605/// A simple key-value store backed by a sorted Vec for small maps.
606#[allow(dead_code)]
607pub struct SmallMap<K: Ord + Clone, V: Clone> {
608    entries: Vec<(K, V)>,
609}
610#[allow(dead_code)]
611impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
612    /// Creates a new empty small map.
613    pub fn new() -> Self {
614        Self {
615            entries: Vec::new(),
616        }
617    }
618    /// Inserts or replaces the value for `key`.
619    pub fn insert(&mut self, key: K, val: V) {
620        match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
621            Ok(i) => self.entries[i].1 = val,
622            Err(i) => self.entries.insert(i, (key, val)),
623        }
624    }
625    /// Returns the value for `key`, or `None`.
626    pub fn get(&self, key: &K) -> Option<&V> {
627        self.entries
628            .binary_search_by_key(&key, |(k, _)| k)
629            .ok()
630            .map(|i| &self.entries[i].1)
631    }
632    /// Returns the number of entries.
633    pub fn len(&self) -> usize {
634        self.entries.len()
635    }
636    /// Returns `true` if empty.
637    pub fn is_empty(&self) -> bool {
638        self.entries.is_empty()
639    }
640    /// Returns all keys.
641    pub fn keys(&self) -> Vec<&K> {
642        self.entries.iter().map(|(k, _)| k).collect()
643    }
644    /// Returns all values.
645    pub fn values(&self) -> Vec<&V> {
646        self.entries.iter().map(|(_, v)| v).collect()
647    }
648}
649/// A generic counter that tracks min/max/sum for statistical summaries.
650#[allow(dead_code)]
651pub struct StatSummary {
652    count: u64,
653    sum: f64,
654    min: f64,
655    max: f64,
656}
657#[allow(dead_code)]
658impl StatSummary {
659    /// Creates an empty summary.
660    pub fn new() -> Self {
661        Self {
662            count: 0,
663            sum: 0.0,
664            min: f64::INFINITY,
665            max: f64::NEG_INFINITY,
666        }
667    }
668    /// Records a sample.
669    pub fn record(&mut self, val: f64) {
670        self.count += 1;
671        self.sum += val;
672        if val < self.min {
673            self.min = val;
674        }
675        if val > self.max {
676            self.max = val;
677        }
678    }
679    /// Returns the mean, or `None` if no samples.
680    pub fn mean(&self) -> Option<f64> {
681        if self.count == 0 {
682            None
683        } else {
684            Some(self.sum / self.count as f64)
685        }
686    }
687    /// Returns the minimum, or `None` if no samples.
688    pub fn min(&self) -> Option<f64> {
689        if self.count == 0 {
690            None
691        } else {
692            Some(self.min)
693        }
694    }
695    /// Returns the maximum, or `None` if no samples.
696    pub fn max(&self) -> Option<f64> {
697        if self.count == 0 {
698            None
699        } else {
700            Some(self.max)
701        }
702    }
703    /// Returns the count of recorded samples.
704    pub fn count(&self) -> u64 {
705        self.count
706    }
707}
708/// A pool of reusable string buffers.
709#[allow(dead_code)]
710pub struct StringPool {
711    free: Vec<String>,
712}
713#[allow(dead_code)]
714impl StringPool {
715    /// Creates a new empty string pool.
716    pub fn new() -> Self {
717        Self { free: Vec::new() }
718    }
719    /// Takes a string from the pool (may be empty).
720    pub fn take(&mut self) -> String {
721        self.free.pop().unwrap_or_default()
722    }
723    /// Returns a string to the pool.
724    pub fn give(&mut self, mut s: String) {
725        s.clear();
726        self.free.push(s);
727    }
728    /// Returns the number of free strings in the pool.
729    pub fn free_count(&self) -> usize {
730        self.free.len()
731    }
732}
733/// A tagged union for representing a simple two-case discriminated union.
734#[allow(dead_code)]
735pub enum Either2<A, B> {
736    /// The first alternative.
737    First(A),
738    /// The second alternative.
739    Second(B),
740}
741#[allow(dead_code)]
742impl<A, B> Either2<A, B> {
743    /// Returns `true` if this is the first alternative.
744    pub fn is_first(&self) -> bool {
745        matches!(self, Either2::First(_))
746    }
747    /// Returns `true` if this is the second alternative.
748    pub fn is_second(&self) -> bool {
749        matches!(self, Either2::Second(_))
750    }
751    /// Returns the first value if present.
752    pub fn first(self) -> Option<A> {
753        match self {
754            Either2::First(a) => Some(a),
755            _ => None,
756        }
757    }
758    /// Returns the second value if present.
759    pub fn second(self) -> Option<B> {
760        match self {
761            Either2::Second(b) => Some(b),
762            _ => None,
763        }
764    }
765    /// Maps over the first alternative.
766    pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
767        match self {
768            Either2::First(a) => Either2::First(f(a)),
769            Either2::Second(b) => Either2::Second(b),
770        }
771    }
772}
773/// A trie-based prefix counter.
774#[allow(dead_code)]
775pub struct PrefixCounter {
776    children: std::collections::HashMap<char, PrefixCounter>,
777    count: usize,
778}
779#[allow(dead_code)]
780impl PrefixCounter {
781    /// Creates an empty prefix counter.
782    pub fn new() -> Self {
783        Self {
784            children: std::collections::HashMap::new(),
785            count: 0,
786        }
787    }
788    /// Records a string.
789    pub fn record(&mut self, s: &str) {
790        self.count += 1;
791        let mut node = self;
792        for c in s.chars() {
793            node = node.children.entry(c).or_default();
794            node.count += 1;
795        }
796    }
797    /// Returns how many strings have been recorded that start with `prefix`.
798    pub fn count_with_prefix(&self, prefix: &str) -> usize {
799        let mut node = self;
800        for c in prefix.chars() {
801            match node.children.get(&c) {
802                Some(n) => node = n,
803                None => return 0,
804            }
805        }
806        node.count
807    }
808}
809/// A simple mutable key-value store for test fixtures.
810#[allow(dead_code)]
811pub struct Fixture {
812    data: std::collections::HashMap<String, String>,
813}
814#[allow(dead_code)]
815impl Fixture {
816    /// Creates an empty fixture.
817    pub fn new() -> Self {
818        Self {
819            data: std::collections::HashMap::new(),
820        }
821    }
822    /// Sets a key.
823    pub fn set(&mut self, key: impl Into<String>, val: impl Into<String>) {
824        self.data.insert(key.into(), val.into());
825    }
826    /// Gets a value.
827    pub fn get(&self, key: &str) -> Option<&str> {
828        self.data.get(key).map(|s| s.as_str())
829    }
830    /// Returns the number of entries.
831    pub fn len(&self) -> usize {
832        self.data.len()
833    }
834    /// Returns whether the collection is empty.
835    pub fn is_empty(&self) -> bool {
836        self.len() == 0
837    }
838}
839/// A window iterator that yields overlapping windows of size `n`.
840#[allow(dead_code)]
841pub struct WindowIterator<'a, T> {
842    pub(super) data: &'a [T],
843    pub(super) pos: usize,
844    pub(super) window: usize,
845}
846#[allow(dead_code)]
847impl<'a, T> WindowIterator<'a, T> {
848    /// Creates a new window iterator.
849    pub fn new(data: &'a [T], window: usize) -> Self {
850        Self {
851            data,
852            pos: 0,
853            window,
854        }
855    }
856}
857/// A non-empty list (at least one element guaranteed).
858#[allow(dead_code)]
859pub struct NonEmptyVec<T> {
860    head: T,
861    tail: Vec<T>,
862}
863#[allow(dead_code)]
864impl<T> NonEmptyVec<T> {
865    /// Creates a non-empty vec with a single element.
866    pub fn singleton(val: T) -> Self {
867        Self {
868            head: val,
869            tail: Vec::new(),
870        }
871    }
872    /// Pushes an element.
873    pub fn push(&mut self, val: T) {
874        self.tail.push(val);
875    }
876    /// Returns a reference to the first element.
877    pub fn first(&self) -> &T {
878        &self.head
879    }
880    /// Returns a reference to the last element.
881    pub fn last(&self) -> &T {
882        self.tail.last().unwrap_or(&self.head)
883    }
884    /// Returns the number of elements.
885    pub fn len(&self) -> usize {
886        1 + self.tail.len()
887    }
888    /// Returns whether the collection is empty.
889    pub fn is_empty(&self) -> bool {
890        self.len() == 0
891    }
892    /// Returns all elements as a Vec.
893    pub fn to_vec(&self) -> Vec<&T> {
894        let mut v = vec![&self.head];
895        v.extend(self.tail.iter());
896        v
897    }
898}
899/// A type-erased function pointer with arity tracking.
900#[allow(dead_code)]
901pub struct RawFnPtr {
902    /// The raw function pointer (stored as usize for type erasure).
903    ptr: usize,
904    arity: usize,
905    name: String,
906}
907#[allow(dead_code)]
908impl RawFnPtr {
909    /// Creates a new raw function pointer descriptor.
910    pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
911        Self {
912            ptr,
913            arity,
914            name: name.into(),
915        }
916    }
917    /// Returns the arity.
918    pub fn arity(&self) -> usize {
919        self.arity
920    }
921    /// Returns the name.
922    pub fn name(&self) -> &str {
923        &self.name
924    }
925    /// Returns the raw pointer value.
926    pub fn raw(&self) -> usize {
927        self.ptr
928    }
929}
930/// A dependency closure builder (transitive closure via BFS).
931#[allow(dead_code)]
932pub struct TransitiveClosure {
933    adj: Vec<Vec<usize>>,
934    n: usize,
935}
936#[allow(dead_code)]
937impl TransitiveClosure {
938    /// Creates a transitive closure builder for `n` nodes.
939    pub fn new(n: usize) -> Self {
940        Self {
941            adj: vec![Vec::new(); n],
942            n,
943        }
944    }
945    /// Adds a direct edge.
946    pub fn add_edge(&mut self, from: usize, to: usize) {
947        if from < self.n {
948            self.adj[from].push(to);
949        }
950    }
951    /// Computes all nodes reachable from `start` (including `start`).
952    pub fn reachable_from(&self, start: usize) -> Vec<usize> {
953        let mut visited = vec![false; self.n];
954        let mut queue = std::collections::VecDeque::new();
955        queue.push_back(start);
956        while let Some(node) = queue.pop_front() {
957            if node >= self.n || visited[node] {
958                continue;
959            }
960            visited[node] = true;
961            for &next in &self.adj[node] {
962                queue.push_back(next);
963            }
964        }
965        (0..self.n).filter(|&i| visited[i]).collect()
966    }
967    /// Returns `true` if `from` can transitively reach `to`.
968    pub fn can_reach(&self, from: usize, to: usize) -> bool {
969        self.reachable_from(from).contains(&to)
970    }
971}
972/// A pair of `StatSummary` values tracking before/after a transformation.
973#[allow(dead_code)]
974pub struct TransformStat {
975    before: StatSummary,
976    after: StatSummary,
977}
978#[allow(dead_code)]
979impl TransformStat {
980    /// Creates a new transform stat recorder.
981    pub fn new() -> Self {
982        Self {
983            before: StatSummary::new(),
984            after: StatSummary::new(),
985        }
986    }
987    /// Records a before value.
988    pub fn record_before(&mut self, v: f64) {
989        self.before.record(v);
990    }
991    /// Records an after value.
992    pub fn record_after(&mut self, v: f64) {
993        self.after.record(v);
994    }
995    /// Returns the mean reduction ratio (after/before).
996    pub fn mean_ratio(&self) -> Option<f64> {
997        let b = self.before.mean()?;
998        let a = self.after.mean()?;
999        if b.abs() < f64::EPSILON {
1000            return None;
1001        }
1002        Some(a / b)
1003    }
1004}
1005/// A hierarchical configuration tree.
1006#[allow(dead_code)]
1007pub struct ConfigNode {
1008    key: String,
1009    value: Option<String>,
1010    children: Vec<ConfigNode>,
1011}
1012#[allow(dead_code)]
1013impl ConfigNode {
1014    /// Creates a leaf config node with a value.
1015    pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
1016        Self {
1017            key: key.into(),
1018            value: Some(value.into()),
1019            children: Vec::new(),
1020        }
1021    }
1022    /// Creates a section node with children.
1023    pub fn section(key: impl Into<String>) -> Self {
1024        Self {
1025            key: key.into(),
1026            value: None,
1027            children: Vec::new(),
1028        }
1029    }
1030    /// Adds a child node.
1031    pub fn add_child(&mut self, child: ConfigNode) {
1032        self.children.push(child);
1033    }
1034    /// Returns the key.
1035    pub fn key(&self) -> &str {
1036        &self.key
1037    }
1038    /// Returns the value, or `None` for section nodes.
1039    pub fn value(&self) -> Option<&str> {
1040        self.value.as_deref()
1041    }
1042    /// Returns the number of children.
1043    pub fn num_children(&self) -> usize {
1044        self.children.len()
1045    }
1046    /// Looks up a dot-separated path.
1047    pub fn lookup(&self, path: &str) -> Option<&str> {
1048        let mut parts = path.splitn(2, '.');
1049        let head = parts.next()?;
1050        let tail = parts.next();
1051        if head != self.key {
1052            return None;
1053        }
1054        match tail {
1055            None => self.value.as_deref(),
1056            Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1057        }
1058    }
1059    fn lookup_relative(&self, path: &str) -> Option<&str> {
1060        let mut parts = path.splitn(2, '.');
1061        let head = parts.next()?;
1062        let tail = parts.next();
1063        if head != self.key {
1064            return None;
1065        }
1066        match tail {
1067            None => self.value.as_deref(),
1068            Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1069        }
1070    }
1071}
1072/// A versioned record that stores a history of values.
1073#[allow(dead_code)]
1074pub struct VersionedRecord<T: Clone> {
1075    history: Vec<T>,
1076}
1077#[allow(dead_code)]
1078impl<T: Clone> VersionedRecord<T> {
1079    /// Creates a new record with an initial value.
1080    pub fn new(initial: T) -> Self {
1081        Self {
1082            history: vec![initial],
1083        }
1084    }
1085    /// Updates the record with a new version.
1086    pub fn update(&mut self, val: T) {
1087        self.history.push(val);
1088    }
1089    /// Returns the current (latest) value.
1090    pub fn current(&self) -> &T {
1091        self.history
1092            .last()
1093            .expect("VersionedRecord history is always non-empty after construction")
1094    }
1095    /// Returns the value at version `n` (0-indexed), or `None`.
1096    pub fn at_version(&self, n: usize) -> Option<&T> {
1097        self.history.get(n)
1098    }
1099    /// Returns the version number of the current value.
1100    pub fn version(&self) -> usize {
1101        self.history.len() - 1
1102    }
1103    /// Returns `true` if more than one version exists.
1104    pub fn has_history(&self) -> bool {
1105        self.history.len() > 1
1106    }
1107}
1108/// A min-heap implemented as a binary heap.
1109#[allow(dead_code)]
1110pub struct MinHeap<T: Ord> {
1111    data: Vec<T>,
1112}
1113#[allow(dead_code)]
1114impl<T: Ord> MinHeap<T> {
1115    /// Creates a new empty min-heap.
1116    pub fn new() -> Self {
1117        Self { data: Vec::new() }
1118    }
1119    /// Inserts an element.
1120    pub fn push(&mut self, val: T) {
1121        self.data.push(val);
1122        self.sift_up(self.data.len() - 1);
1123    }
1124    /// Removes and returns the minimum element.
1125    pub fn pop(&mut self) -> Option<T> {
1126        if self.data.is_empty() {
1127            return None;
1128        }
1129        let n = self.data.len();
1130        self.data.swap(0, n - 1);
1131        let min = self.data.pop();
1132        if !self.data.is_empty() {
1133            self.sift_down(0);
1134        }
1135        min
1136    }
1137    /// Returns a reference to the minimum element.
1138    pub fn peek(&self) -> Option<&T> {
1139        self.data.first()
1140    }
1141    /// Returns the number of elements.
1142    pub fn len(&self) -> usize {
1143        self.data.len()
1144    }
1145    /// Returns `true` if empty.
1146    pub fn is_empty(&self) -> bool {
1147        self.data.is_empty()
1148    }
1149    fn sift_up(&mut self, mut i: usize) {
1150        while i > 0 {
1151            let parent = (i - 1) / 2;
1152            if self.data[i] < self.data[parent] {
1153                self.data.swap(i, parent);
1154                i = parent;
1155            } else {
1156                break;
1157            }
1158        }
1159    }
1160    fn sift_down(&mut self, mut i: usize) {
1161        let n = self.data.len();
1162        loop {
1163            let left = 2 * i + 1;
1164            let right = 2 * i + 2;
1165            let mut smallest = i;
1166            if left < n && self.data[left] < self.data[smallest] {
1167                smallest = left;
1168            }
1169            if right < n && self.data[right] < self.data[smallest] {
1170                smallest = right;
1171            }
1172            if smallest == i {
1173                break;
1174            }
1175            self.data.swap(i, smallest);
1176            i = smallest;
1177        }
1178    }
1179}