Skip to main content

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