Skip to main content

oxilean_kernel/alpha/
types.rs

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