Skip to main content

oxilean_kernel/level/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use crate::Name;
6
7use std::collections::HashMap;
8use std::rc::Rc;
9
10use super::functions::{is_equivalent, is_leq};
11
12/// A simple decision tree node for rule dispatching.
13#[allow(dead_code)]
14#[allow(missing_docs)]
15pub enum DecisionNode {
16    /// A leaf with an action string.
17    Leaf(String),
18    /// An interior node: check `key` equals `val` → `yes_branch`, else `no_branch`.
19    Branch {
20        key: String,
21        val: String,
22        yes_branch: Box<DecisionNode>,
23        no_branch: Box<DecisionNode>,
24    },
25}
26#[allow(dead_code)]
27impl DecisionNode {
28    /// Evaluates the decision tree with the given context.
29    pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
30        match self {
31            DecisionNode::Leaf(action) => action.as_str(),
32            DecisionNode::Branch {
33                key,
34                val,
35                yes_branch,
36                no_branch,
37            } => {
38                let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
39                if actual == val.as_str() {
40                    yes_branch.evaluate(ctx)
41                } else {
42                    no_branch.evaluate(ctx)
43                }
44            }
45        }
46    }
47    /// Returns the depth of the decision tree.
48    pub fn depth(&self) -> usize {
49        match self {
50            DecisionNode::Leaf(_) => 0,
51            DecisionNode::Branch {
52                yes_branch,
53                no_branch,
54                ..
55            } => 1 + yes_branch.depth().max(no_branch.depth()),
56        }
57    }
58}
59/// A flat list of substitution pairs `(from, to)`.
60#[allow(dead_code)]
61pub struct FlatSubstitution {
62    pairs: Vec<(String, String)>,
63}
64#[allow(dead_code)]
65impl FlatSubstitution {
66    /// Creates an empty substitution.
67    pub fn new() -> Self {
68        Self { pairs: Vec::new() }
69    }
70    /// Adds a pair.
71    pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
72        self.pairs.push((from.into(), to.into()));
73    }
74    /// Applies all substitutions to `s` (leftmost-first order).
75    pub fn apply(&self, s: &str) -> String {
76        let mut result = s.to_string();
77        for (from, to) in &self.pairs {
78            result = result.replace(from.as_str(), to.as_str());
79        }
80        result
81    }
82    /// Returns the number of pairs.
83    pub fn len(&self) -> usize {
84        self.pairs.len()
85    }
86    /// Returns `true` if empty.
87    pub fn is_empty(&self) -> bool {
88        self.pairs.is_empty()
89    }
90}
91/// A level constraint: an assertion that l1 ≤ l2 or l1 = l2.
92#[allow(dead_code)]
93#[derive(Debug, Clone, PartialEq)]
94pub enum LevelConstraint {
95    /// l1 ≤ l2
96    Leq(Level, Level),
97    /// l1 = l2 (syntactic equality after normalization)
98    Eq(Level, Level),
99}
100impl LevelConstraint {
101    /// Check whether this constraint is satisfied.
102    ///
103    /// Uses `is_leq` / `is_equivalent` from this module.
104    #[allow(dead_code)]
105    pub fn is_satisfied(&self) -> bool {
106        match self {
107            LevelConstraint::Leq(l1, l2) => is_leq(l1, l2),
108            LevelConstraint::Eq(l1, l2) => is_equivalent(l1, l2),
109        }
110    }
111    /// Return both levels involved in this constraint.
112    #[allow(dead_code)]
113    pub fn levels(&self) -> (&Level, &Level) {
114        match self {
115            LevelConstraint::Leq(l1, l2) | LevelConstraint::Eq(l1, l2) => (l1, l2),
116        }
117    }
118}
119/// A hierarchical configuration tree.
120#[allow(dead_code)]
121pub struct ConfigNode {
122    key: String,
123    value: Option<String>,
124    children: Vec<ConfigNode>,
125}
126#[allow(dead_code)]
127impl ConfigNode {
128    /// Creates a leaf config node with a value.
129    pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
130        Self {
131            key: key.into(),
132            value: Some(value.into()),
133            children: Vec::new(),
134        }
135    }
136    /// Creates a section node with children.
137    pub fn section(key: impl Into<String>) -> Self {
138        Self {
139            key: key.into(),
140            value: None,
141            children: Vec::new(),
142        }
143    }
144    /// Adds a child node.
145    pub fn add_child(&mut self, child: ConfigNode) {
146        self.children.push(child);
147    }
148    /// Returns the key.
149    pub fn key(&self) -> &str {
150        &self.key
151    }
152    /// Returns the value, or `None` for section nodes.
153    pub fn value(&self) -> Option<&str> {
154        self.value.as_deref()
155    }
156    /// Returns the number of children.
157    pub fn num_children(&self) -> usize {
158        self.children.len()
159    }
160    /// Looks up a dot-separated path.
161    pub fn lookup(&self, path: &str) -> Option<&str> {
162        let mut parts = path.splitn(2, '.');
163        let head = parts.next()?;
164        let tail = parts.next();
165        if head != self.key {
166            return None;
167        }
168        match tail {
169            None => self.value.as_deref(),
170            Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
171        }
172    }
173    fn lookup_relative(&self, path: &str) -> Option<&str> {
174        let mut parts = path.splitn(2, '.');
175        let head = parts.next()?;
176        let tail = parts.next();
177        if head != self.key {
178            return None;
179        }
180        match tail {
181            None => self.value.as_deref(),
182            Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
183        }
184    }
185}
186/// A window iterator that yields overlapping windows of size `n`.
187#[allow(dead_code)]
188pub struct WindowIterator<'a, T> {
189    pub(super) data: &'a [T],
190    pub(super) pos: usize,
191    pub(super) window: usize,
192}
193#[allow(dead_code)]
194impl<'a, T> WindowIterator<'a, T> {
195    /// Creates a new window iterator.
196    pub fn new(data: &'a [T], window: usize) -> Self {
197        Self {
198            data,
199            pos: 0,
200            window,
201        }
202    }
203}
204/// A counter that can measure elapsed time between snapshots.
205#[allow(dead_code)]
206pub struct Stopwatch {
207    start: crate::wall_clock::Instant,
208    splits: Vec<f64>,
209}
210#[allow(dead_code)]
211impl Stopwatch {
212    /// Creates and starts a new stopwatch.
213    pub fn start() -> Self {
214        Self {
215            start: crate::wall_clock::Instant::now(),
216            splits: Vec::new(),
217        }
218    }
219    /// Records a split time (elapsed since start).
220    pub fn split(&mut self) {
221        self.splits.push(self.elapsed_ms());
222    }
223    /// Returns total elapsed milliseconds since start.
224    pub fn elapsed_ms(&self) -> f64 {
225        self.start.elapsed().as_secs_f64() * 1000.0
226    }
227    /// Returns all recorded split times.
228    pub fn splits(&self) -> &[f64] {
229        &self.splits
230    }
231    /// Returns the number of splits.
232    pub fn num_splits(&self) -> usize {
233        self.splits.len()
234    }
235}
236/// A write-once cell.
237#[allow(dead_code)]
238pub struct WriteOnce<T> {
239    value: std::cell::Cell<Option<T>>,
240}
241#[allow(dead_code)]
242impl<T: Copy> WriteOnce<T> {
243    /// Creates an empty write-once cell.
244    pub fn new() -> Self {
245        Self {
246            value: std::cell::Cell::new(None),
247        }
248    }
249    /// Writes a value.  Returns `false` if already written.
250    pub fn write(&self, val: T) -> bool {
251        if self.value.get().is_some() {
252            return false;
253        }
254        self.value.set(Some(val));
255        true
256    }
257    /// Returns the value if written.
258    pub fn read(&self) -> Option<T> {
259        self.value.get()
260    }
261    /// Returns `true` if the value has been written.
262    pub fn is_written(&self) -> bool {
263        self.value.get().is_some()
264    }
265}
266/// A tagged union for representing a simple two-case discriminated union.
267#[allow(dead_code)]
268pub enum Either2<A, B> {
269    /// The first alternative.
270    First(A),
271    /// The second alternative.
272    Second(B),
273}
274#[allow(dead_code)]
275impl<A, B> Either2<A, B> {
276    /// Returns `true` if this is the first alternative.
277    pub fn is_first(&self) -> bool {
278        matches!(self, Either2::First(_))
279    }
280    /// Returns `true` if this is the second alternative.
281    pub fn is_second(&self) -> bool {
282        matches!(self, Either2::Second(_))
283    }
284    /// Returns the first value if present.
285    pub fn first(self) -> Option<A> {
286        match self {
287            Either2::First(a) => Some(a),
288            _ => None,
289        }
290    }
291    /// Returns the second value if present.
292    pub fn second(self) -> Option<B> {
293        match self {
294            Either2::Second(b) => Some(b),
295            _ => None,
296        }
297    }
298    /// Maps over the first alternative.
299    pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
300        match self {
301            Either2::First(a) => Either2::First(f(a)),
302            Either2::Second(b) => Either2::Second(b),
303        }
304    }
305}
306/// A versioned record that stores a history of values.
307#[allow(dead_code)]
308pub struct VersionedRecord<T: Clone> {
309    /// Every earlier value, oldest first: version `n` is `earlier[n]`.
310    earlier: Vec<T>,
311    /// The latest value (version `earlier.len()`), declared last so it drops last.
312    current: T,
313}
314#[allow(dead_code)]
315impl<T: Clone> VersionedRecord<T> {
316    /// Creates a new record with an initial value.
317    pub fn new(initial: T) -> Self {
318        Self {
319            earlier: Vec::new(),
320            current: initial,
321        }
322    }
323    /// Updates the record with a new version.
324    pub fn update(&mut self, val: T) {
325        let previous = std::mem::replace(&mut self.current, val);
326        self.earlier.push(previous);
327    }
328    /// Returns the current (latest) value.
329    pub fn current(&self) -> &T {
330        &self.current
331    }
332    /// Returns the value at version `n` (0-indexed), or `None`.
333    pub fn at_version(&self, n: usize) -> Option<&T> {
334        match self.earlier.get(n) {
335            Some(value) => Some(value),
336            None if n == self.earlier.len() => Some(&self.current),
337            None => None,
338        }
339    }
340    /// Returns the version number of the current value.
341    pub fn version(&self) -> usize {
342        self.earlier.len()
343    }
344    /// Returns `true` if more than one version exists.
345    pub fn has_history(&self) -> bool {
346        !self.earlier.is_empty()
347    }
348}
349/// A simple mutable key-value store for test fixtures.
350#[allow(dead_code)]
351pub struct Fixture {
352    data: std::collections::HashMap<String, String>,
353}
354#[allow(dead_code)]
355impl Fixture {
356    /// Creates an empty fixture.
357    pub fn new() -> Self {
358        Self {
359            data: std::collections::HashMap::new(),
360        }
361    }
362    /// Sets a key.
363    pub fn set(&mut self, key: impl Into<String>, val: impl Into<String>) {
364        self.data.insert(key.into(), val.into());
365    }
366    /// Gets a value.
367    pub fn get(&self, key: &str) -> Option<&str> {
368        self.data.get(key).map(|s| s.as_str())
369    }
370    /// Returns the number of entries.
371    pub fn len(&self) -> usize {
372        self.data.len()
373    }
374    /// Returns whether the collection is empty.
375    pub fn is_empty(&self) -> bool {
376        self.len() == 0
377    }
378}
379/// A type-erased function pointer with arity tracking.
380#[allow(dead_code)]
381pub struct RawFnPtr {
382    /// The raw function pointer (stored as usize for type erasure).
383    ptr: usize,
384    arity: usize,
385    name: String,
386}
387#[allow(dead_code)]
388impl RawFnPtr {
389    /// Creates a new raw function pointer descriptor.
390    pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
391        Self {
392            ptr,
393            arity,
394            name: name.into(),
395        }
396    }
397    /// Returns the arity.
398    pub fn arity(&self) -> usize {
399        self.arity
400    }
401    /// Returns the name.
402    pub fn name(&self) -> &str {
403        &self.name
404    }
405    /// Returns the raw pointer value.
406    pub fn raw(&self) -> usize {
407        self.ptr
408    }
409}
410/// A mutable reference stack for tracking the current "focus" in a tree traversal.
411#[allow(dead_code)]
412pub struct FocusStack<T> {
413    items: Vec<T>,
414}
415#[allow(dead_code)]
416impl<T> FocusStack<T> {
417    /// Creates an empty focus stack.
418    pub fn new() -> Self {
419        Self { items: Vec::new() }
420    }
421    /// Focuses on `item`.
422    pub fn focus(&mut self, item: T) {
423        self.items.push(item);
424    }
425    /// Blurs (pops) the current focus.
426    pub fn blur(&mut self) -> Option<T> {
427        self.items.pop()
428    }
429    /// Returns the current focus, or `None`.
430    pub fn current(&self) -> Option<&T> {
431        self.items.last()
432    }
433    /// Returns the focus depth.
434    pub fn depth(&self) -> usize {
435        self.items.len()
436    }
437    /// Returns `true` if there is no current focus.
438    pub fn is_empty(&self) -> bool {
439        self.items.is_empty()
440    }
441}
442/// A dependency closure builder (transitive closure via BFS).
443#[allow(dead_code)]
444pub struct TransitiveClosure {
445    adj: Vec<Vec<usize>>,
446    n: usize,
447}
448#[allow(dead_code)]
449impl TransitiveClosure {
450    /// Creates a transitive closure builder for `n` nodes.
451    pub fn new(n: usize) -> Self {
452        Self {
453            adj: vec![Vec::new(); n],
454            n,
455        }
456    }
457    /// Adds a direct edge.
458    pub fn add_edge(&mut self, from: usize, to: usize) {
459        if from < self.n {
460            self.adj[from].push(to);
461        }
462    }
463    /// Computes all nodes reachable from `start` (including `start`).
464    pub fn reachable_from(&self, start: usize) -> Vec<usize> {
465        let mut visited = vec![false; self.n];
466        let mut queue = std::collections::VecDeque::new();
467        queue.push_back(start);
468        while let Some(node) = queue.pop_front() {
469            if node >= self.n || visited[node] {
470                continue;
471            }
472            visited[node] = true;
473            for &next in &self.adj[node] {
474                queue.push_back(next);
475            }
476        }
477        (0..self.n).filter(|&i| visited[i]).collect()
478    }
479    /// Returns `true` if `from` can transitively reach `to`.
480    pub fn can_reach(&self, from: usize, to: usize) -> bool {
481        self.reachable_from(from).contains(&to)
482    }
483}
484/// A label set for a graph node.
485#[allow(dead_code)]
486pub struct LabelSet {
487    labels: Vec<String>,
488}
489#[allow(dead_code)]
490impl LabelSet {
491    /// Creates a new empty label set.
492    pub fn new() -> Self {
493        Self { labels: Vec::new() }
494    }
495    /// Adds a label (deduplicates).
496    pub fn add(&mut self, label: impl Into<String>) {
497        let s = label.into();
498        if !self.labels.contains(&s) {
499            self.labels.push(s);
500        }
501    }
502    /// Returns `true` if `label` is present.
503    pub fn has(&self, label: &str) -> bool {
504        self.labels.iter().any(|l| l == label)
505    }
506    /// Returns the count of labels.
507    pub fn count(&self) -> usize {
508        self.labels.len()
509    }
510    /// Returns all labels.
511    pub fn all(&self) -> &[String] {
512        &self.labels
513    }
514}
515/// A set of rewrite rules.
516#[allow(dead_code)]
517pub struct RewriteRuleSet {
518    rules: Vec<RewriteRule>,
519}
520#[allow(dead_code)]
521impl RewriteRuleSet {
522    /// Creates an empty rule set.
523    pub fn new() -> Self {
524        Self { rules: Vec::new() }
525    }
526    /// Adds a rule.
527    pub fn add(&mut self, rule: RewriteRule) {
528        self.rules.push(rule);
529    }
530    /// Returns the number of rules.
531    pub fn len(&self) -> usize {
532        self.rules.len()
533    }
534    /// Returns `true` if the set is empty.
535    pub fn is_empty(&self) -> bool {
536        self.rules.is_empty()
537    }
538    /// Returns all conditional rules.
539    pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
540        self.rules.iter().filter(|r| r.conditional).collect()
541    }
542    /// Returns all unconditional rules.
543    pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
544        self.rules.iter().filter(|r| !r.conditional).collect()
545    }
546    /// Looks up a rule by name.
547    pub fn get(&self, name: &str) -> Option<&RewriteRule> {
548        self.rules.iter().find(|r| r.name == name)
549    }
550}
551/// A simple key-value store backed by a sorted Vec for small maps.
552#[allow(dead_code)]
553pub struct SmallMap<K: Ord + Clone, V: Clone> {
554    entries: Vec<(K, V)>,
555}
556#[allow(dead_code)]
557impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
558    /// Creates a new empty small map.
559    pub fn new() -> Self {
560        Self {
561            entries: Vec::new(),
562        }
563    }
564    /// Inserts or replaces the value for `key`.
565    pub fn insert(&mut self, key: K, val: V) {
566        match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
567            Ok(i) => self.entries[i].1 = val,
568            Err(i) => self.entries.insert(i, (key, val)),
569        }
570    }
571    /// Returns the value for `key`, or `None`.
572    pub fn get(&self, key: &K) -> Option<&V> {
573        self.entries
574            .binary_search_by_key(&key, |(k, _)| k)
575            .ok()
576            .map(|i| &self.entries[i].1)
577    }
578    /// Returns the number of entries.
579    pub fn len(&self) -> usize {
580        self.entries.len()
581    }
582    /// Returns `true` if empty.
583    pub fn is_empty(&self) -> bool {
584        self.entries.is_empty()
585    }
586    /// Returns all keys.
587    pub fn keys(&self) -> Vec<&K> {
588        self.entries.iter().map(|(k, _)| k).collect()
589    }
590    /// Returns all values.
591    pub fn values(&self) -> Vec<&V> {
592        self.entries.iter().map(|(_, v)| v).collect()
593    }
594}
595/// A token bucket rate limiter.
596#[allow(dead_code)]
597pub struct TokenBucket {
598    capacity: u64,
599    tokens: u64,
600    refill_per_ms: u64,
601    last_refill: crate::wall_clock::Instant,
602}
603#[allow(dead_code)]
604impl TokenBucket {
605    /// Creates a new token bucket.
606    pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
607        Self {
608            capacity,
609            tokens: capacity,
610            refill_per_ms,
611            last_refill: crate::wall_clock::Instant::now(),
612        }
613    }
614    /// Attempts to consume `n` tokens.  Returns `true` on success.
615    pub fn try_consume(&mut self, n: u64) -> bool {
616        self.refill();
617        if self.tokens >= n {
618            self.tokens -= n;
619            true
620        } else {
621            false
622        }
623    }
624    fn refill(&mut self) {
625        let now = crate::wall_clock::Instant::now();
626        let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
627        if elapsed_ms > 0 {
628            let new_tokens = elapsed_ms * self.refill_per_ms;
629            self.tokens = (self.tokens + new_tokens).min(self.capacity);
630            self.last_refill = now;
631        }
632    }
633    /// Returns the number of currently available tokens.
634    pub fn available(&self) -> u64 {
635        self.tokens
636    }
637    /// Returns the bucket capacity.
638    pub fn capacity(&self) -> u64 {
639        self.capacity
640    }
641}
642/// A simple stack-based calculator for arithmetic expressions.
643#[allow(dead_code)]
644pub struct StackCalc {
645    stack: Vec<i64>,
646}
647#[allow(dead_code)]
648impl StackCalc {
649    /// Creates a new empty calculator.
650    pub fn new() -> Self {
651        Self { stack: Vec::new() }
652    }
653    /// Pushes an integer literal.
654    pub fn push(&mut self, n: i64) {
655        self.stack.push(n);
656    }
657    /// Replaces the top two values, `b` on top of `a`, with `op(a, b)` and
658    /// returns it.  Returns `None`, leaving the stack unchanged, if it holds
659    /// fewer than two values.
660    fn apply_binary(&mut self, op: impl FnOnce(i64, i64) -> i64) -> Option<i64> {
661        let (rest_len, a, b) = match self.stack[..] {
662            [ref rest @ .., a, b] => (rest.len(), a, b),
663            _ => return None,
664        };
665        let value = op(a, b);
666        self.stack.truncate(rest_len);
667        self.stack.push(value);
668        Some(value)
669    }
670    /// Adds the top two values and returns the sum, which replaces them.
671    /// Returns `None`, leaving the stack unchanged, if it holds fewer than
672    /// two values.
673    pub fn add(&mut self) -> Option<i64> {
674        self.apply_binary(|a, b| a + b)
675    }
676    /// Subtracts top from second and returns the difference, which replaces
677    /// them.  Returns `None`, leaving the stack unchanged, if it holds fewer
678    /// than two values.
679    pub fn sub(&mut self) -> Option<i64> {
680        self.apply_binary(|a, b| a - b)
681    }
682    /// Multiplies the top two values and returns the product, which replaces
683    /// them.  Returns `None`, leaving the stack unchanged, if it holds fewer
684    /// than two values.
685    pub fn mul(&mut self) -> Option<i64> {
686        self.apply_binary(|a, b| a * b)
687    }
688    /// Peeks the top value.
689    pub fn peek(&self) -> Option<i64> {
690        self.stack.last().copied()
691    }
692    /// Returns the stack depth.
693    pub fn depth(&self) -> usize {
694        self.stack.len()
695    }
696}
697/// Represents a rewrite rule `lhs → rhs`.
698#[allow(dead_code)]
699#[allow(missing_docs)]
700pub struct RewriteRule {
701    /// The name of the rule.
702    pub name: String,
703    /// A string representation of the LHS pattern.
704    pub lhs: String,
705    /// A string representation of the RHS.
706    pub rhs: String,
707    /// Whether this is a conditional rule (has side conditions).
708    pub conditional: bool,
709}
710#[allow(dead_code)]
711impl RewriteRule {
712    /// Creates an unconditional rewrite rule.
713    pub fn unconditional(
714        name: impl Into<String>,
715        lhs: impl Into<String>,
716        rhs: impl Into<String>,
717    ) -> Self {
718        Self {
719            name: name.into(),
720            lhs: lhs.into(),
721            rhs: rhs.into(),
722            conditional: false,
723        }
724    }
725    /// Creates a conditional rewrite rule.
726    pub fn conditional(
727        name: impl Into<String>,
728        lhs: impl Into<String>,
729        rhs: impl Into<String>,
730    ) -> Self {
731        Self {
732            name: name.into(),
733            lhs: lhs.into(),
734            rhs: rhs.into(),
735            conditional: true,
736        }
737    }
738    /// Returns a textual representation.
739    pub fn display(&self) -> String {
740        format!("{}: {} → {}", self.name, self.lhs, self.rhs)
741    }
742}
743/// A constraint set: a collection of level constraints.
744#[allow(dead_code)]
745#[derive(Debug, Default, Clone)]
746pub struct ConstraintSet {
747    constraints: Vec<LevelConstraint>,
748}
749impl ConstraintSet {
750    /// Create an empty constraint set.
751    #[allow(dead_code)]
752    pub fn new() -> Self {
753        Self::default()
754    }
755    /// Add a constraint.
756    #[allow(dead_code)]
757    pub fn add(&mut self, c: LevelConstraint) {
758        self.constraints.push(c);
759    }
760    /// Add a ≤ constraint.
761    #[allow(dead_code)]
762    pub fn add_leq(&mut self, l1: Level, l2: Level) {
763        self.add(LevelConstraint::Leq(l1, l2));
764    }
765    /// Add an = constraint.
766    #[allow(dead_code)]
767    pub fn add_eq(&mut self, l1: Level, l2: Level) {
768        self.add(LevelConstraint::Eq(l1, l2));
769    }
770    /// Check if all constraints are satisfied.
771    #[allow(dead_code)]
772    pub fn all_satisfied(&self) -> bool {
773        self.constraints.iter().all(|c| c.is_satisfied())
774    }
775    /// Return unsatisfied constraints.
776    #[allow(dead_code)]
777    pub fn unsatisfied(&self) -> Vec<&LevelConstraint> {
778        self.constraints
779            .iter()
780            .filter(|c| !c.is_satisfied())
781            .collect()
782    }
783    /// Number of constraints.
784    #[allow(dead_code)]
785    pub fn len(&self) -> usize {
786        self.constraints.len()
787    }
788    /// Whether the set is empty.
789    #[allow(dead_code)]
790    pub fn is_empty(&self) -> bool {
791        self.constraints.is_empty()
792    }
793}
794/// A fixed-size sliding window that computes a running sum.
795#[allow(dead_code)]
796pub struct SlidingSum {
797    window: Vec<f64>,
798    capacity: usize,
799    pos: usize,
800    sum: f64,
801    count: usize,
802}
803#[allow(dead_code)]
804impl SlidingSum {
805    /// Creates a sliding sum with the given window size.
806    pub fn new(capacity: usize) -> Self {
807        Self {
808            window: vec![0.0; capacity],
809            capacity,
810            pos: 0,
811            sum: 0.0,
812            count: 0,
813        }
814    }
815    /// Adds a value to the window, removing the oldest if full.
816    pub fn push(&mut self, val: f64) {
817        let oldest = self.window[self.pos];
818        self.sum -= oldest;
819        self.sum += val;
820        self.window[self.pos] = val;
821        self.pos = (self.pos + 1) % self.capacity;
822        if self.count < self.capacity {
823            self.count += 1;
824        }
825    }
826    /// Returns the current window sum.
827    pub fn sum(&self) -> f64 {
828        self.sum
829    }
830    /// Returns the window mean, or `None` if empty.
831    pub fn mean(&self) -> Option<f64> {
832        if self.count == 0 {
833            None
834        } else {
835            Some(self.sum / self.count as f64)
836        }
837    }
838    /// Returns the current window size (number of valid elements).
839    pub fn count(&self) -> usize {
840        self.count
841    }
842}
843/// A reusable scratch buffer for path computations.
844#[allow(dead_code)]
845pub struct PathBuf {
846    components: Vec<String>,
847}
848#[allow(dead_code)]
849impl PathBuf {
850    /// Creates a new empty path buffer.
851    pub fn new() -> Self {
852        Self {
853            components: Vec::new(),
854        }
855    }
856    /// Pushes a component.
857    pub fn push(&mut self, comp: impl Into<String>) {
858        self.components.push(comp.into());
859    }
860    /// Pops the last component.
861    pub fn pop(&mut self) {
862        self.components.pop();
863    }
864    /// Returns the current path as a `/`-separated string.
865    pub fn as_str(&self) -> String {
866        self.components.join("/")
867    }
868    /// Returns the depth of the path.
869    pub fn depth(&self) -> usize {
870        self.components.len()
871    }
872    /// Clears the path.
873    pub fn clear(&mut self) {
874        self.components.clear();
875    }
876}
877/// A non-empty list (at least one element guaranteed).
878#[allow(dead_code)]
879pub struct NonEmptyVec<T> {
880    head: T,
881    tail: Vec<T>,
882}
883#[allow(dead_code)]
884impl<T> NonEmptyVec<T> {
885    /// Creates a non-empty vec with a single element.
886    pub fn singleton(val: T) -> Self {
887        Self {
888            head: val,
889            tail: Vec::new(),
890        }
891    }
892    /// Pushes an element.
893    pub fn push(&mut self, val: T) {
894        self.tail.push(val);
895    }
896    /// Returns a reference to the first element.
897    pub fn first(&self) -> &T {
898        &self.head
899    }
900    /// Returns a reference to the last element.
901    pub fn last(&self) -> &T {
902        self.tail.last().unwrap_or(&self.head)
903    }
904    /// Returns the number of elements.
905    pub fn len(&self) -> usize {
906        1 + self.tail.len()
907    }
908    /// Returns whether the collection is empty.
909    pub fn is_empty(&self) -> bool {
910        self.len() == 0
911    }
912    /// Returns all elements as a Vec.
913    pub fn to_vec(&self) -> Vec<&T> {
914        let mut v = vec![&self.head];
915        v.extend(self.tail.iter());
916        v
917    }
918}
919/// A pool of reusable string buffers.
920#[allow(dead_code)]
921pub struct StringPool {
922    free: Vec<String>,
923}
924#[allow(dead_code)]
925impl StringPool {
926    /// Creates a new empty string pool.
927    pub fn new() -> Self {
928        Self { free: Vec::new() }
929    }
930    /// Takes a string from the pool (may be empty).
931    pub fn take(&mut self) -> String {
932        self.free.pop().unwrap_or_default()
933    }
934    /// Returns a string to the pool.
935    pub fn give(&mut self, mut s: String) {
936        s.clear();
937        self.free.push(s);
938    }
939    /// Returns the number of free strings in the pool.
940    pub fn free_count(&self) -> usize {
941        self.free.len()
942    }
943}
944/// A generic counter that tracks min/max/sum for statistical summaries.
945#[allow(dead_code)]
946pub struct StatSummary {
947    count: u64,
948    sum: f64,
949    min: f64,
950    max: f64,
951}
952#[allow(dead_code)]
953impl StatSummary {
954    /// Creates an empty summary.
955    pub fn new() -> Self {
956        Self {
957            count: 0,
958            sum: 0.0,
959            min: f64::INFINITY,
960            max: f64::NEG_INFINITY,
961        }
962    }
963    /// Records a sample.
964    pub fn record(&mut self, val: f64) {
965        self.count += 1;
966        self.sum += val;
967        if val < self.min {
968            self.min = val;
969        }
970        if val > self.max {
971            self.max = val;
972        }
973    }
974    /// Returns the mean, or `None` if no samples.
975    pub fn mean(&self) -> Option<f64> {
976        if self.count == 0 {
977            None
978        } else {
979            Some(self.sum / self.count as f64)
980        }
981    }
982    /// Returns the minimum, or `None` if no samples.
983    pub fn min(&self) -> Option<f64> {
984        if self.count == 0 {
985            None
986        } else {
987            Some(self.min)
988        }
989    }
990    /// Returns the maximum, or `None` if no samples.
991    pub fn max(&self) -> Option<f64> {
992        if self.count == 0 {
993            None
994        } else {
995            Some(self.max)
996        }
997    }
998    /// Returns the count of recorded samples.
999    pub fn count(&self) -> u64 {
1000        self.count
1001    }
1002}
1003/// A simple directed acyclic graph.
1004#[allow(dead_code)]
1005pub struct SimpleDag {
1006    /// `edges[i]` is the list of direct successors of node `i`.
1007    edges: Vec<Vec<usize>>,
1008}
1009#[allow(dead_code)]
1010impl SimpleDag {
1011    /// Creates a DAG with `n` nodes and no edges.
1012    pub fn new(n: usize) -> Self {
1013        Self {
1014            edges: vec![Vec::new(); n],
1015        }
1016    }
1017    /// Adds an edge from `from` to `to`.
1018    pub fn add_edge(&mut self, from: usize, to: usize) {
1019        if from < self.edges.len() {
1020            self.edges[from].push(to);
1021        }
1022    }
1023    /// Returns the successors of `node`.
1024    pub fn successors(&self, node: usize) -> &[usize] {
1025        self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
1026    }
1027    /// Returns `true` if `from` can reach `to` via DFS.
1028    pub fn can_reach(&self, from: usize, to: usize) -> bool {
1029        let mut visited = vec![false; self.edges.len()];
1030        self.dfs(from, to, &mut visited)
1031    }
1032    fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
1033        if cur == target {
1034            return true;
1035        }
1036        if cur >= visited.len() || visited[cur] {
1037            return false;
1038        }
1039        visited[cur] = true;
1040        for &next in self.successors(cur) {
1041            if self.dfs(next, target, visited) {
1042                return true;
1043            }
1044        }
1045        false
1046    }
1047    /// Returns the topological order of nodes, or `None` if a cycle is detected.
1048    pub fn topological_sort(&self) -> Option<Vec<usize>> {
1049        let n = self.edges.len();
1050        let mut in_degree = vec![0usize; n];
1051        for succs in &self.edges {
1052            for &s in succs {
1053                if s < n {
1054                    in_degree[s] += 1;
1055                }
1056            }
1057        }
1058        let mut queue: std::collections::VecDeque<usize> =
1059            (0..n).filter(|&i| in_degree[i] == 0).collect();
1060        let mut order = Vec::new();
1061        while let Some(node) = queue.pop_front() {
1062            order.push(node);
1063            for &s in self.successors(node) {
1064                if s < n {
1065                    in_degree[s] -= 1;
1066                    if in_degree[s] == 0 {
1067                        queue.push_back(s);
1068                    }
1069                }
1070            }
1071        }
1072        if order.len() == n {
1073            Some(order)
1074        } else {
1075            None
1076        }
1077    }
1078    /// Returns the number of nodes.
1079    pub fn num_nodes(&self) -> usize {
1080        self.edges.len()
1081    }
1082}
1083/// A universe level.
1084///
1085/// Levels form expressions over zero, successor, max, imax, parameters,
1086/// and metavariables.
1087///
1088/// Structural sharing (wave5 Stage F): `Level` is a newtype over a
1089/// reference-counted cell holding its outermost node (`LevelKind`), so cloning
1090/// a whole level — e.g. every element of the `Vec<Level>` a `Const` carries —
1091/// is an O(1) refcount bump, and sub-levels are shared by pointer.
1092/// Match on the outermost node through [`Level::view`].
1093///
1094/// Each level also stores a hash of its own structure, computed when it is
1095/// built from the stored hashes of its sub-levels (see the kernel-private
1096/// `structural_hash` module) — so an `Expr` that carries levels (a `Sort`, a
1097/// `Const`) folds them into its own hash in O(1) each, without walking them.
1098///
1099/// Equality is exactly structural: the same allocation is equal, different
1100/// stored hashes are different (equal levels always hash equal), and
1101/// otherwise the nodes are compared. `Hash` writes the structure as it always
1102/// did (not the stored hash), so a `HashMap<Level, _>` behaves as before.
1103#[derive(Clone)]
1104pub struct Level(Rc<LevelCell>);
1105
1106/// The shared allocation behind a [`Level`]: its node kind, and the hash of
1107/// its structure.
1108///
1109/// Invariant: `hash` is the structural hash of `kind`, set where the cell is
1110/// built (the constructors below) and never changed — a `Level` gives no
1111/// mutable access to its cell.
1112struct LevelCell {
1113    hash: u64,
1114    kind: LevelKind,
1115}
1116
1117impl PartialEq for Level {
1118    #[inline]
1119    fn eq(&self, other: &Level) -> bool {
1120        Rc::ptr_eq(&self.0, &other.0)
1121            || (self.0.hash == other.0.hash && self.0.kind == other.0.kind)
1122    }
1123}
1124impl Eq for Level {}
1125impl std::hash::Hash for Level {
1126    /// Writes the structure, exactly as the derived implementation did when
1127    /// `Level` wrapped the node kind directly.
1128    #[inline]
1129    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1130        self.0.kind.hash(state);
1131    }
1132}
1133impl std::fmt::Debug for Level {
1134    /// Formats as `Level(<kind>)` — the output of the derived implementation
1135    /// when `Level` wrapped the node kind directly. Code that hashes or
1136    /// orders terms by their `Debug` text depends on this spelling.
1137    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1138        f.debug_tuple("Level").field(&self.0.kind).finish()
1139    }
1140}
1141
1142/// The node kind behind a [`Level`]. Private: construct through [`Level`]'s
1143/// constructors and inspect through [`Level::view`] and the accessor methods.
1144#[derive(PartialEq, Eq, Hash, Debug)]
1145enum LevelKind {
1146    /// Level 0 (Prop).
1147    Zero,
1148    /// Successor: u + 1.
1149    Succ(Level),
1150    /// Maximum of two levels: max(u, v).
1151    Max(Level, Level),
1152    /// Impredicative maximum: imax(u, v).
1153    ///
1154    /// Semantics: imax(u, v) = 0 if v = 0, else max(u, v).
1155    /// This ensures Prop -> Prop : Prop (impredicativity).
1156    IMax(Level, Level),
1157    /// Universe parameter (for polymorphism).
1158    Param(Name),
1159    /// Universe metavariable (for unification).
1160    MVar(LevelMVarId),
1161}
1162
1163/// A borrowed view of a [`Level`]'s outermost node, for pattern matching.
1164///
1165/// Obtained from [`Level::view`]; mirrors the former public `Level` enum shape.
1166pub enum LevelView<'a> {
1167    /// Level 0 (Prop).
1168    Zero,
1169    /// Successor: u + 1.
1170    Succ(&'a Level),
1171    /// Maximum of two levels: max(u, v).
1172    Max(&'a Level, &'a Level),
1173    /// Impredicative maximum: imax(u, v).
1174    IMax(&'a Level, &'a Level),
1175    /// Universe parameter (for polymorphism).
1176    Param(&'a Name),
1177    /// Universe metavariable (for unification).
1178    MVar(LevelMVarId),
1179}
1180
1181impl Level {
1182    /// Borrow this level's outermost node for matching. O(1).
1183    #[inline]
1184    pub fn view(&self) -> LevelView<'_> {
1185        match &self.0.kind {
1186            LevelKind::Zero => LevelView::Zero,
1187            LevelKind::Succ(l) => LevelView::Succ(l),
1188            LevelKind::Max(a, b) => LevelView::Max(a, b),
1189            LevelKind::IMax(a, b) => LevelView::IMax(a, b),
1190            LevelKind::Param(n) => LevelView::Param(n),
1191            LevelKind::MVar(id) => LevelView::MVar(*id),
1192        }
1193    }
1194    /// The hash of this level's structure, stored when the level was built.
1195    /// O(1). Equal levels have equal hashes; see [`crate::structural_hash`].
1196    #[inline]
1197    #[must_use]
1198    pub(crate) fn structural_hash(&self) -> u64 {
1199        self.0.hash
1200    }
1201    /// Wrap a node kind with the hash of its structure. The only place a
1202    /// [`LevelCell`] is built.
1203    #[inline]
1204    fn from_kind(kind: LevelKind) -> Self {
1205        use crate::structural_hash::{
1206            mix, LEVEL_IMAX, LEVEL_MAX, LEVEL_MVAR, LEVEL_PARAM, LEVEL_SUCC, LEVEL_ZERO,
1207        };
1208        let hash = match &kind {
1209            LevelKind::Zero => LEVEL_ZERO,
1210            LevelKind::Succ(l) => mix(LEVEL_SUCC, l.0.hash),
1211            LevelKind::Max(l1, l2) => mix(mix(LEVEL_MAX, l1.0.hash), l2.0.hash),
1212            LevelKind::IMax(l1, l2) => mix(mix(LEVEL_IMAX, l1.0.hash), l2.0.hash),
1213            LevelKind::Param(name) => mix(LEVEL_PARAM, name.structural_hash()),
1214            LevelKind::MVar(id) => mix(LEVEL_MVAR, id.0),
1215        };
1216        Level(Rc::new(LevelCell { hash, kind }))
1217    }
1218    /// Create Zero level.
1219    pub fn zero() -> Self {
1220        Level::from_kind(LevelKind::Zero)
1221    }
1222    /// Create a successor level.
1223    pub fn succ(l: Level) -> Self {
1224        Level::from_kind(LevelKind::Succ(l))
1225    }
1226    /// Create a max level.
1227    pub fn max(l1: Level, l2: Level) -> Self {
1228        Level::from_kind(LevelKind::Max(l1, l2))
1229    }
1230    /// Create an imax level.
1231    pub fn imax(l1: Level, l2: Level) -> Self {
1232        Level::from_kind(LevelKind::IMax(l1, l2))
1233    }
1234    /// Create a parameter level.
1235    pub fn param(name: Name) -> Self {
1236        Level::from_kind(LevelKind::Param(name))
1237    }
1238    /// Create a level metavariable.
1239    pub fn mvar(id: LevelMVarId) -> Self {
1240        Level::from_kind(LevelKind::MVar(id))
1241    }
1242    /// Check if this is Zero.
1243    pub fn is_zero(&self) -> bool {
1244        matches!(&self.0.kind, LevelKind::Zero)
1245    }
1246    /// Check if this is a parameter.
1247    pub fn is_param(&self) -> bool {
1248        matches!(&self.0.kind, LevelKind::Param(_))
1249    }
1250    /// Check if this is a metavariable.
1251    pub fn is_mvar(&self) -> bool {
1252        matches!(&self.0.kind, LevelKind::MVar(_))
1253    }
1254    /// Check if this is a successor.
1255    pub fn is_succ(&self) -> bool {
1256        matches!(&self.0.kind, LevelKind::Succ(_))
1257    }
1258    /// Check if this is a max.
1259    pub fn is_max(&self) -> bool {
1260        matches!(&self.0.kind, LevelKind::Max(_, _))
1261    }
1262    /// Check if this is an imax.
1263    pub fn is_imax(&self) -> bool {
1264        matches!(&self.0.kind, LevelKind::IMax(_, _))
1265    }
1266    /// Check if this level is definitely not zero.
1267    ///
1268    /// Returns true if we can statically determine this is >= 1.
1269    pub fn is_not_zero(&self) -> bool {
1270        match &self.0.kind {
1271            LevelKind::Zero => false,
1272            LevelKind::Succ(_) => true,
1273            LevelKind::Max(l1, l2) => l1.is_not_zero() || l2.is_not_zero(),
1274            LevelKind::IMax(_, l2) => l2.is_not_zero(),
1275            LevelKind::Param(_) | LevelKind::MVar(_) => false,
1276        }
1277    }
1278    /// Check if this level contains any metavariables.
1279    pub fn has_mvar(&self) -> bool {
1280        match &self.0.kind {
1281            LevelKind::MVar(_) => true,
1282            LevelKind::Succ(l) => l.has_mvar(),
1283            LevelKind::Max(l1, l2) | LevelKind::IMax(l1, l2) => l1.has_mvar() || l2.has_mvar(),
1284            LevelKind::Zero | LevelKind::Param(_) => false,
1285        }
1286    }
1287    /// Check if this level contains any parameters.
1288    pub fn has_param(&self) -> bool {
1289        match &self.0.kind {
1290            LevelKind::Param(_) => true,
1291            LevelKind::Succ(l) => l.has_param(),
1292            LevelKind::Max(l1, l2) | LevelKind::IMax(l1, l2) => l1.has_param() || l2.has_param(),
1293            LevelKind::Zero | LevelKind::MVar(_) => false,
1294        }
1295    }
1296    /// Get the depth (nesting) of this level expression.
1297    pub fn depth(&self) -> usize {
1298        match &self.0.kind {
1299            LevelKind::Zero | LevelKind::Param(_) | LevelKind::MVar(_) => 0,
1300            LevelKind::Succ(l) => 1 + l.depth(),
1301            LevelKind::Max(l1, l2) | LevelKind::IMax(l1, l2) => 1 + l1.depth().max(l2.depth()),
1302        }
1303    }
1304    /// Create a numeric level `succ^n(zero)`.
1305    pub fn from_nat(n: u32) -> Self {
1306        let mut l = Level::zero();
1307        for _ in 0..n {
1308            l = Level::succ(l);
1309        }
1310        l
1311    }
1312    /// Try to convert to a numeric level.
1313    ///
1314    /// Returns `Some(n)` if this is `succ^n(zero)`, `None` otherwise.
1315    pub fn to_nat(&self) -> Option<u32> {
1316        match &self.0.kind {
1317            LevelKind::Zero => Some(0),
1318            LevelKind::Succ(l) => l.to_nat().map(|n| n + 1),
1319            _ => None,
1320        }
1321    }
1322}
1323/// A min-heap implemented as a binary heap.
1324#[allow(dead_code)]
1325pub struct MinHeap<T: Ord> {
1326    data: Vec<T>,
1327}
1328#[allow(dead_code)]
1329impl<T: Ord> MinHeap<T> {
1330    /// Creates a new empty min-heap.
1331    pub fn new() -> Self {
1332        Self { data: Vec::new() }
1333    }
1334    /// Inserts an element.
1335    pub fn push(&mut self, val: T) {
1336        self.data.push(val);
1337        self.sift_up(self.data.len() - 1);
1338    }
1339    /// Removes and returns the minimum element.
1340    pub fn pop(&mut self) -> Option<T> {
1341        if self.data.is_empty() {
1342            return None;
1343        }
1344        let n = self.data.len();
1345        self.data.swap(0, n - 1);
1346        let min = self.data.pop();
1347        if !self.data.is_empty() {
1348            self.sift_down(0);
1349        }
1350        min
1351    }
1352    /// Returns a reference to the minimum element.
1353    pub fn peek(&self) -> Option<&T> {
1354        self.data.first()
1355    }
1356    /// Returns the number of elements.
1357    pub fn len(&self) -> usize {
1358        self.data.len()
1359    }
1360    /// Returns `true` if empty.
1361    pub fn is_empty(&self) -> bool {
1362        self.data.is_empty()
1363    }
1364    fn sift_up(&mut self, mut i: usize) {
1365        while i > 0 {
1366            let parent = (i - 1) / 2;
1367            if self.data[i] < self.data[parent] {
1368                self.data.swap(i, parent);
1369                i = parent;
1370            } else {
1371                break;
1372            }
1373        }
1374    }
1375    fn sift_down(&mut self, mut i: usize) {
1376        let n = self.data.len();
1377        loop {
1378            let left = 2 * i + 1;
1379            let right = 2 * i + 2;
1380            let mut smallest = i;
1381            if left < n && self.data[left] < self.data[smallest] {
1382                smallest = left;
1383            }
1384            if right < n && self.data[right] < self.data[smallest] {
1385                smallest = right;
1386            }
1387            if smallest == i {
1388                break;
1389            }
1390            self.data.swap(i, smallest);
1391            i = smallest;
1392        }
1393    }
1394}
1395/// A pair of `StatSummary` values tracking before/after a transformation.
1396#[allow(dead_code)]
1397pub struct TransformStat {
1398    before: StatSummary,
1399    after: StatSummary,
1400}
1401#[allow(dead_code)]
1402impl TransformStat {
1403    /// Creates a new transform stat recorder.
1404    pub fn new() -> Self {
1405        Self {
1406            before: StatSummary::new(),
1407            after: StatSummary::new(),
1408        }
1409    }
1410    /// Records a before value.
1411    pub fn record_before(&mut self, v: f64) {
1412        self.before.record(v);
1413    }
1414    /// Records an after value.
1415    pub fn record_after(&mut self, v: f64) {
1416        self.after.record(v);
1417    }
1418    /// Returns the mean reduction ratio (after/before).
1419    pub fn mean_ratio(&self) -> Option<f64> {
1420        let b = self.before.mean()?;
1421        let a = self.after.mean()?;
1422        if b.abs() < f64::EPSILON {
1423            return None;
1424        }
1425        Some(a / b)
1426    }
1427}
1428/// Unique identifier for level metavariables.
1429#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
1430pub struct LevelMVarId(pub u64);
1431/// A sparse vector: stores only non-default elements.
1432#[allow(dead_code)]
1433pub struct SparseVec<T: Default + Clone + PartialEq> {
1434    entries: std::collections::HashMap<usize, T>,
1435    default_: T,
1436    logical_len: usize,
1437}
1438#[allow(dead_code)]
1439impl<T: Default + Clone + PartialEq> SparseVec<T> {
1440    /// Creates a new sparse vector with logical length `len`.
1441    pub fn new(len: usize) -> Self {
1442        Self {
1443            entries: std::collections::HashMap::new(),
1444            default_: T::default(),
1445            logical_len: len,
1446        }
1447    }
1448    /// Sets element at `idx`.
1449    pub fn set(&mut self, idx: usize, val: T) {
1450        if val == self.default_ {
1451            self.entries.remove(&idx);
1452        } else {
1453            self.entries.insert(idx, val);
1454        }
1455    }
1456    /// Gets element at `idx`.
1457    pub fn get(&self, idx: usize) -> &T {
1458        self.entries.get(&idx).unwrap_or(&self.default_)
1459    }
1460    /// Returns the logical length.
1461    pub fn len(&self) -> usize {
1462        self.logical_len
1463    }
1464    /// Returns whether the collection is empty.
1465    pub fn is_empty(&self) -> bool {
1466        self.len() == 0
1467    }
1468    /// Returns the number of non-default elements.
1469    pub fn nnz(&self) -> usize {
1470        self.entries.len()
1471    }
1472}
1473/// A trie-based prefix counter.
1474#[allow(dead_code)]
1475pub struct PrefixCounter {
1476    children: std::collections::HashMap<char, PrefixCounter>,
1477    count: usize,
1478}
1479#[allow(dead_code)]
1480impl PrefixCounter {
1481    /// Creates an empty prefix counter.
1482    pub fn new() -> Self {
1483        Self {
1484            children: std::collections::HashMap::new(),
1485            count: 0,
1486        }
1487    }
1488    /// Records a string.
1489    pub fn record(&mut self, s: &str) {
1490        self.count += 1;
1491        let mut node = self;
1492        for c in s.chars() {
1493            node = node.children.entry(c).or_default();
1494            node.count += 1;
1495        }
1496    }
1497    /// Returns how many strings have been recorded that start with `prefix`.
1498    pub fn count_with_prefix(&self, prefix: &str) -> usize {
1499        let mut node = self;
1500        for c in prefix.chars() {
1501            match node.children.get(&c) {
1502                Some(n) => node = n,
1503                None => return 0,
1504            }
1505        }
1506        node.count
1507    }
1508}