Skip to main content

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