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