Skip to main content

oxilean_kernel/builtin/
types.rs

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