Skip to main content

oxilean_kernel/trace/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use crate::Expr;
6use std::time::{Duration, Instant};
7
8use std::collections::HashMap;
9
10/// A versioned record that stores a history of values.
11#[allow(dead_code)]
12pub struct VersionedRecord<T: Clone> {
13    history: Vec<T>,
14}
15#[allow(dead_code)]
16impl<T: Clone> VersionedRecord<T> {
17    /// Creates a new record with an initial value.
18    pub fn new(initial: T) -> Self {
19        Self {
20            history: vec![initial],
21        }
22    }
23    /// Updates the record with a new version.
24    pub fn update(&mut self, val: T) {
25        self.history.push(val);
26    }
27    /// Returns the current (latest) value.
28    pub fn current(&self) -> &T {
29        self.history
30            .last()
31            .expect("VersionedRecord history is always non-empty after construction")
32    }
33    /// Returns the value at version `n` (0-indexed), or `None`.
34    pub fn at_version(&self, n: usize) -> Option<&T> {
35        self.history.get(n)
36    }
37    /// Returns the version number of the current value.
38    pub fn version(&self) -> usize {
39        self.history.len() - 1
40    }
41    /// Returns `true` if more than one version exists.
42    pub fn has_history(&self) -> bool {
43        self.history.len() > 1
44    }
45}
46/// A pair of `StatSummary` values tracking before/after a transformation.
47#[allow(dead_code)]
48pub struct TransformStat {
49    before: StatSummary,
50    after: StatSummary,
51}
52#[allow(dead_code)]
53impl TransformStat {
54    /// Creates a new transform stat recorder.
55    pub fn new() -> Self {
56        Self {
57            before: StatSummary::new(),
58            after: StatSummary::new(),
59        }
60    }
61    /// Records a before value.
62    pub fn record_before(&mut self, v: f64) {
63        self.before.record(v);
64    }
65    /// Records an after value.
66    pub fn record_after(&mut self, v: f64) {
67        self.after.record(v);
68    }
69    /// Returns the mean reduction ratio (after/before).
70    pub fn mean_ratio(&self) -> Option<f64> {
71        let b = self.before.mean()?;
72        let a = self.after.mean()?;
73        if b.abs() < f64::EPSILON {
74            return None;
75        }
76        Some(a / b)
77    }
78}
79/// Tracer for collecting debugging information during type checking.
80pub struct Tracer {
81    level: TraceLevel,
82    events: Vec<TraceEvent>,
83    max_events: usize,
84    reduction_steps: Vec<ReductionStep>,
85    depth: u32,
86    timing_enabled: bool,
87    start_time: Option<Instant>,
88    suppressed_categories: Vec<TraceCategory>,
89}
90impl Tracer {
91    /// Create a new tracer with the given level.
92    pub fn new(level: TraceLevel) -> Self {
93        Self {
94            level,
95            events: Vec::new(),
96            max_events: 1000,
97            reduction_steps: Vec::new(),
98            depth: 0,
99            timing_enabled: false,
100            start_time: None,
101            suppressed_categories: Vec::new(),
102        }
103    }
104    /// Create a silent tracer.
105    pub fn silent() -> Self {
106        Self::new(TraceLevel::Off)
107    }
108    /// Create a fully verbose tracer.
109    pub fn verbose() -> Self {
110        Self::new(TraceLevel::Trace)
111    }
112    /// Set the trace level.
113    pub fn set_level(&mut self, level: TraceLevel) {
114        self.level = level;
115    }
116    /// Get the trace level.
117    pub fn level(&self) -> TraceLevel {
118        self.level
119    }
120    /// Set the max events buffer size.
121    pub fn set_max_events(&mut self, max: usize) {
122        self.max_events = max;
123    }
124    /// Enable or disable timing.
125    pub fn set_timing(&mut self, enabled: bool) {
126        self.timing_enabled = enabled;
127        self.start_time = if enabled { Some(Instant::now()) } else { None };
128    }
129    /// Suppress a category.
130    pub fn suppress(&mut self, cat: TraceCategory) {
131        if !self.suppressed_categories.contains(&cat) {
132            self.suppressed_categories.push(cat);
133        }
134    }
135    /// Allow a category.
136    pub fn allow(&mut self, cat: &TraceCategory) {
137        self.suppressed_categories.retain(|c| c != cat);
138    }
139    /// Log a trace event.
140    pub fn log(&mut self, mut event: TraceEvent) {
141        if event.level > self.level {
142            return;
143        }
144        if let Some(cat) = &event.category {
145            if self.suppressed_categories.contains(cat) {
146                return;
147            }
148        }
149        event.depth = self.depth;
150        if self.events.len() >= self.max_events {
151            self.events.remove(0);
152        }
153        self.events.push(event);
154    }
155    /// Log a string at the given level.
156    pub fn log_msg(&mut self, level: TraceLevel, msg: impl Into<String>) {
157        self.log(TraceEvent::new(level, msg.into()));
158    }
159    /// Log an error.
160    pub fn error(&mut self, msg: impl Into<String>) {
161        self.log_msg(TraceLevel::Error, msg);
162    }
163    /// Log a warning.
164    pub fn warn(&mut self, msg: impl Into<String>) {
165        self.log_msg(TraceLevel::Warn, msg);
166    }
167    /// Log an info message.
168    pub fn info(&mut self, msg: impl Into<String>) {
169        self.log_msg(TraceLevel::Info, msg);
170    }
171    /// Log a debug message.
172    pub fn debug(&mut self, msg: impl Into<String>) {
173        self.log_msg(TraceLevel::Debug, msg);
174    }
175    /// Log a trace message.
176    pub fn trace_msg(&mut self, msg: impl Into<String>) {
177        self.log_msg(TraceLevel::Trace, msg);
178    }
179    /// Log a trace-level message in the Infer category.
180    pub fn trace_infer(&mut self, msg: impl Into<String>) {
181        self.log(
182            TraceEvent::new(TraceLevel::Trace, msg.into()).with_category(TraceCategory::Infer),
183        );
184    }
185    /// Log a trace-level message in the Reduce category.
186    pub fn trace_reduce(&mut self, msg: impl Into<String>) {
187        self.log(
188            TraceEvent::new(TraceLevel::Trace, msg.into()).with_category(TraceCategory::Reduce),
189        );
190    }
191    /// Record a reduction step.
192    pub fn record_reduction(&mut self, rule: ReductionRule, before: Expr, after: Expr) {
193        if self.level >= TraceLevel::Trace {
194            self.reduction_steps.push(ReductionStep {
195                rule,
196                before,
197                after,
198            });
199        }
200    }
201    /// Get reduction steps.
202    pub fn reduction_steps(&self) -> &[ReductionStep] {
203        &self.reduction_steps
204    }
205    /// Clear reduction steps.
206    pub fn clear_reductions(&mut self) {
207        self.reduction_steps.clear();
208    }
209    /// Get all logged events.
210    pub fn events(&self) -> &[TraceEvent] {
211        &self.events
212    }
213    /// Get events at a specific level.
214    pub fn events_at_level(&self, level: TraceLevel) -> Vec<&TraceEvent> {
215        self.events.iter().filter(|e| e.level <= level).collect()
216    }
217    /// Get events in a specific category.
218    pub fn events_in_category(&self, cat: &TraceCategory) -> Vec<&TraceEvent> {
219        self.events
220            .iter()
221            .filter(|e| e.category.as_ref() == Some(cat))
222            .collect()
223    }
224    /// Clear all events.
225    pub fn clear(&mut self) {
226        self.events.clear();
227    }
228    /// Count events.
229    pub fn event_count(&self) -> usize {
230        self.events.len()
231    }
232    /// Push depth.
233    pub fn push(&mut self) {
234        self.depth += 1;
235    }
236    /// Pop depth.
237    pub fn pop(&mut self) {
238        if self.depth > 0 {
239            self.depth -= 1;
240        }
241    }
242    /// Get current depth.
243    pub fn current_depth(&self) -> u32 {
244        self.depth
245    }
246    /// Get elapsed time since tracing started.
247    pub fn elapsed(&self) -> Option<Duration> {
248        self.start_time.map(|t| t.elapsed())
249    }
250    /// Render all events as a multi-line string.
251    pub fn render(&self) -> String {
252        self.events
253            .iter()
254            .map(|e| e.format())
255            .collect::<Vec<_>>()
256            .join("\n")
257    }
258}
259/// Extension trait for `Tracer` providing convenience methods.
260impl Tracer {
261    /// Log and return a message at Debug level.
262    pub fn debug_return<T>(&mut self, value: T, msg: impl Into<String>) -> T {
263        self.debug(msg);
264        value
265    }
266    /// Log an expression at Debug level.
267    pub fn debug_expr(&mut self, label: &str, expr: &Expr) {
268        self.debug(format!("{}: {:?}", label, expr));
269    }
270    /// Compute statistics for this tracer.
271    pub fn stats(&self) -> TracerStats {
272        TracerStats::compute(self)
273    }
274    /// Return the most recent event, if any.
275    pub fn last_event(&self) -> Option<&TraceEvent> {
276        self.events().last()
277    }
278    /// Return the most recent error event, if any.
279    pub fn last_error(&self) -> Option<&TraceEvent> {
280        self.events()
281            .iter()
282            .rev()
283            .find(|e| e.level == TraceLevel::Error)
284    }
285    /// Check whether the tracer has any events.
286    pub fn is_empty(&self) -> bool {
287        self.events().is_empty()
288    }
289    /// Log with a specific category.
290    pub fn log_with_category(
291        &mut self,
292        level: TraceLevel,
293        category: TraceCategory,
294        msg: impl Into<String>,
295    ) {
296        self.log(TraceEvent::new(level, msg.into()).with_category(category));
297    }
298    /// Log an infer event at Debug level.
299    pub fn log_infer(&mut self, msg: impl Into<String>) {
300        self.log_with_category(TraceLevel::Debug, TraceCategory::Infer, msg);
301    }
302    /// Log a simp event at Trace level.
303    pub fn log_simp(&mut self, msg: impl Into<String>) {
304        self.log_with_category(TraceLevel::Trace, TraceCategory::Simp, msg);
305    }
306    /// Log a tactic event at Info level.
307    pub fn log_tactic(&mut self, msg: impl Into<String>) {
308        self.log_with_category(TraceLevel::Info, TraceCategory::Tactic, msg);
309    }
310    /// Log an elaboration event at Debug level.
311    pub fn log_elab(&mut self, msg: impl Into<String>) {
312        self.log_with_category(TraceLevel::Debug, TraceCategory::Elab, msg);
313    }
314    /// Return all events in a given category as formatted strings.
315    pub fn category_log(&self, cat: &TraceCategory) -> Vec<String> {
316        self.events_in_category(cat)
317            .iter()
318            .map(|e| e.format())
319            .collect()
320    }
321    /// Clear only events in a given category.
322    pub fn clear_category(&mut self, cat: &TraceCategory) {
323        self.info(format!("[cleared category {}]", cat));
324    }
325}
326/// Represents a rewrite rule `lhs → rhs`.
327#[allow(dead_code)]
328#[allow(missing_docs)]
329pub struct RewriteRule {
330    /// The name of the rule.
331    pub name: String,
332    /// A string representation of the LHS pattern.
333    pub lhs: String,
334    /// A string representation of the RHS.
335    pub rhs: String,
336    /// Whether this is a conditional rule (has side conditions).
337    pub conditional: bool,
338}
339#[allow(dead_code)]
340impl RewriteRule {
341    /// Creates an unconditional rewrite rule.
342    pub fn unconditional(
343        name: impl Into<String>,
344        lhs: impl Into<String>,
345        rhs: impl Into<String>,
346    ) -> Self {
347        Self {
348            name: name.into(),
349            lhs: lhs.into(),
350            rhs: rhs.into(),
351            conditional: false,
352        }
353    }
354    /// Creates a conditional rewrite rule.
355    pub fn conditional(
356        name: impl Into<String>,
357        lhs: impl Into<String>,
358        rhs: impl Into<String>,
359    ) -> Self {
360        Self {
361            name: name.into(),
362            lhs: lhs.into(),
363            rhs: rhs.into(),
364            conditional: true,
365        }
366    }
367    /// Returns a textual representation.
368    pub fn display(&self) -> String {
369        format!("{}: {} → {}", self.name, self.lhs, self.rhs)
370    }
371}
372/// A simple stack-based calculator for arithmetic expressions.
373#[allow(dead_code)]
374pub struct StackCalc {
375    stack: Vec<i64>,
376}
377#[allow(dead_code)]
378impl StackCalc {
379    /// Creates a new empty calculator.
380    pub fn new() -> Self {
381        Self { stack: Vec::new() }
382    }
383    /// Pushes an integer literal.
384    pub fn push(&mut self, n: i64) {
385        self.stack.push(n);
386    }
387    /// Adds the top two values.  Panics if fewer than two values.
388    pub fn add(&mut self) {
389        let b = self
390            .stack
391            .pop()
392            .expect("stack must have at least two values for add");
393        let a = self
394            .stack
395            .pop()
396            .expect("stack must have at least two values for add");
397        self.stack.push(a + b);
398    }
399    /// Subtracts top from second.
400    pub fn sub(&mut self) {
401        let b = self
402            .stack
403            .pop()
404            .expect("stack must have at least two values for sub");
405        let a = self
406            .stack
407            .pop()
408            .expect("stack must have at least two values for sub");
409        self.stack.push(a - b);
410    }
411    /// Multiplies the top two values.
412    pub fn mul(&mut self) {
413        let b = self
414            .stack
415            .pop()
416            .expect("stack must have at least two values for mul");
417        let a = self
418            .stack
419            .pop()
420            .expect("stack must have at least two values for mul");
421        self.stack.push(a * b);
422    }
423    /// Peeks the top value.
424    pub fn peek(&self) -> Option<i64> {
425        self.stack.last().copied()
426    }
427    /// Returns the stack depth.
428    pub fn depth(&self) -> usize {
429        self.stack.len()
430    }
431}
432/// A hierarchical span for structured tracing.
433pub struct TraceSpan<'a> {
434    pub(crate) tracer: &'a mut Tracer,
435    pub(crate) name: &'static str,
436}
437impl<'a> TraceSpan<'a> {
438    /// Open a new span, pushing depth.
439    pub fn open(tracer: &'a mut Tracer, name: &'static str) -> Self {
440        tracer.info(format!(">>> {}", name));
441        tracer.push();
442        Self { tracer, name }
443    }
444    /// Log within the span.
445    pub fn log(&mut self, msg: impl Into<String>) {
446        self.tracer.info(msg);
447    }
448    /// Close the span, popping depth.
449    pub fn close(self) {}
450}
451/// A mutable reference stack for tracking the current "focus" in a tree traversal.
452#[allow(dead_code)]
453pub struct FocusStack<T> {
454    items: Vec<T>,
455}
456#[allow(dead_code)]
457impl<T> FocusStack<T> {
458    /// Creates an empty focus stack.
459    pub fn new() -> Self {
460        Self { items: Vec::new() }
461    }
462    /// Focuses on `item`.
463    pub fn focus(&mut self, item: T) {
464        self.items.push(item);
465    }
466    /// Blurs (pops) the current focus.
467    pub fn blur(&mut self) -> Option<T> {
468        self.items.pop()
469    }
470    /// Returns the current focus, or `None`.
471    pub fn current(&self) -> Option<&T> {
472        self.items.last()
473    }
474    /// Returns the focus depth.
475    pub fn depth(&self) -> usize {
476        self.items.len()
477    }
478    /// Returns `true` if there is no current focus.
479    pub fn is_empty(&self) -> bool {
480        self.items.is_empty()
481    }
482}
483/// A non-empty list (at least one element guaranteed).
484#[allow(dead_code)]
485pub struct NonEmptyVec<T> {
486    head: T,
487    tail: Vec<T>,
488}
489#[allow(dead_code)]
490impl<T> NonEmptyVec<T> {
491    /// Creates a non-empty vec with a single element.
492    pub fn singleton(val: T) -> Self {
493        Self {
494            head: val,
495            tail: Vec::new(),
496        }
497    }
498    /// Pushes an element.
499    pub fn push(&mut self, val: T) {
500        self.tail.push(val);
501    }
502    /// Returns a reference to the first element.
503    pub fn first(&self) -> &T {
504        &self.head
505    }
506    /// Returns a reference to the last element.
507    pub fn last(&self) -> &T {
508        self.tail.last().unwrap_or(&self.head)
509    }
510    /// Returns the number of elements.
511    pub fn len(&self) -> usize {
512        1 + self.tail.len()
513    }
514    /// Returns whether the collection is empty.
515    pub fn is_empty(&self) -> bool {
516        self.len() == 0
517    }
518    /// Returns all elements as a Vec.
519    pub fn to_vec(&self) -> Vec<&T> {
520        let mut v = vec![&self.head];
521        v.extend(self.tail.iter());
522        v
523    }
524}
525/// A flat list of substitution pairs `(from, to)`.
526#[allow(dead_code)]
527pub struct FlatSubstitution {
528    pairs: Vec<(String, String)>,
529}
530#[allow(dead_code)]
531impl FlatSubstitution {
532    /// Creates an empty substitution.
533    pub fn new() -> Self {
534        Self { pairs: Vec::new() }
535    }
536    /// Adds a pair.
537    pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
538        self.pairs.push((from.into(), to.into()));
539    }
540    /// Applies all substitutions to `s` (leftmost-first order).
541    pub fn apply(&self, s: &str) -> String {
542        let mut result = s.to_string();
543        for (from, to) in &self.pairs {
544            result = result.replace(from.as_str(), to.as_str());
545        }
546        result
547    }
548    /// Returns the number of pairs.
549    pub fn len(&self) -> usize {
550        self.pairs.len()
551    }
552    /// Returns `true` if empty.
553    pub fn is_empty(&self) -> bool {
554        self.pairs.is_empty()
555    }
556}
557/// A filter for trace events.
558#[derive(Clone, Debug)]
559pub struct TraceFilter {
560    /// Minimum level to include.
561    pub min_level: TraceLevel,
562    /// If set, only include events in these categories.
563    pub categories: Option<Vec<TraceCategory>>,
564    /// If set, exclude events matching this text.
565    pub exclude_text: Option<String>,
566}
567impl TraceFilter {
568    /// Create a filter that accepts everything at the given level.
569    pub fn at_level(level: TraceLevel) -> Self {
570        Self {
571            min_level: level,
572            categories: None,
573            exclude_text: None,
574        }
575    }
576    /// Restrict to specific categories.
577    pub fn with_categories(mut self, cats: Vec<TraceCategory>) -> Self {
578        self.categories = Some(cats);
579        self
580    }
581    /// Exclude events containing specific text.
582    pub fn excluding(mut self, text: impl Into<String>) -> Self {
583        self.exclude_text = Some(text.into());
584        self
585    }
586    /// Check if a trace event passes this filter.
587    ///
588    /// An event is accepted when its level is at most `min_level` in verbosity
589    /// (i.e., at least as important / severe as `min_level`). More verbose
590    /// events (Debug, Trace) are filtered out when `min_level` is lower
591    /// (e.g., Info).
592    pub fn accepts(&self, event: &TraceEvent) -> bool {
593        if event.level > self.min_level {
594            return false;
595        }
596        if let Some(ref cats) = self.categories {
597            if let Some(ref ec) = event.category {
598                if !cats.contains(ec) {
599                    return false;
600                }
601            } else {
602                return false;
603            }
604        }
605        if let Some(ref excl) = self.exclude_text {
606            if event.message.contains(excl.as_str()) {
607                return false;
608            }
609        }
610        true
611    }
612}
613/// A fixed-size sliding window that computes a running sum.
614#[allow(dead_code)]
615pub struct SlidingSum {
616    window: Vec<f64>,
617    capacity: usize,
618    pos: usize,
619    sum: f64,
620    count: usize,
621}
622#[allow(dead_code)]
623impl SlidingSum {
624    /// Creates a sliding sum with the given window size.
625    pub fn new(capacity: usize) -> Self {
626        Self {
627            window: vec![0.0; capacity],
628            capacity,
629            pos: 0,
630            sum: 0.0,
631            count: 0,
632        }
633    }
634    /// Adds a value to the window, removing the oldest if full.
635    pub fn push(&mut self, val: f64) {
636        let oldest = self.window[self.pos];
637        self.sum -= oldest;
638        self.sum += val;
639        self.window[self.pos] = val;
640        self.pos = (self.pos + 1) % self.capacity;
641        if self.count < self.capacity {
642            self.count += 1;
643        }
644    }
645    /// Returns the current window sum.
646    pub fn sum(&self) -> f64 {
647        self.sum
648    }
649    /// Returns the window mean, or `None` if empty.
650    pub fn mean(&self) -> Option<f64> {
651        if self.count == 0 {
652            None
653        } else {
654            Some(self.sum / self.count as f64)
655        }
656    }
657    /// Returns the current window size (number of valid elements).
658    pub fn count(&self) -> usize {
659        self.count
660    }
661}
662/// A reduction step recorded during tracing.
663#[derive(Debug, Clone)]
664pub struct ReductionStep {
665    /// Reduction rule applied.
666    pub rule: ReductionRule,
667    /// Expression before reduction.
668    pub before: Expr,
669    /// Expression after reduction.
670    pub after: Expr,
671}
672/// A window iterator that yields overlapping windows of size `n`.
673#[allow(dead_code)]
674pub struct WindowIterator<'a, T> {
675    pub(super) data: &'a [T],
676    pub(super) pos: usize,
677    pub(super) window: usize,
678}
679#[allow(dead_code)]
680impl<'a, T> WindowIterator<'a, T> {
681    /// Creates a new window iterator.
682    pub fn new(data: &'a [T], window: usize) -> Self {
683        Self {
684            data,
685            pos: 0,
686            window,
687        }
688    }
689}
690/// A ring buffer for trace events that overwrites the oldest entries.
691pub struct RingTracer {
692    buffer: Vec<TraceEvent>,
693    capacity: usize,
694    head: usize,
695    count: usize,
696    level: TraceLevel,
697}
698impl RingTracer {
699    /// Create a ring tracer with the given capacity and level.
700    pub fn new(capacity: usize, level: TraceLevel) -> Self {
701        Self {
702            buffer: Vec::with_capacity(capacity),
703            capacity,
704            head: 0,
705            count: 0,
706            level,
707        }
708    }
709    /// Log a trace event (overwrites oldest if full).
710    pub fn log(&mut self, event: TraceEvent) {
711        if event.level > self.level {
712            return;
713        }
714        if self.buffer.len() < self.capacity {
715            self.buffer.push(event);
716        } else {
717            self.buffer[self.head] = event;
718            self.head = (self.head + 1) % self.capacity;
719        }
720        self.count += 1;
721    }
722    /// Log a message at the given level.
723    pub fn log_msg(&mut self, level: TraceLevel, msg: impl Into<String>) {
724        self.log(TraceEvent::new(level, msg.into()));
725    }
726    /// Return the number of events currently stored.
727    pub fn stored_count(&self) -> usize {
728        self.buffer.len()
729    }
730    /// Return the total number of events logged (including overwritten ones).
731    pub fn total_count(&self) -> usize {
732        self.count
733    }
734    /// Clear all stored events.
735    pub fn clear(&mut self) {
736        self.buffer.clear();
737        self.head = 0;
738        self.count = 0;
739    }
740    /// Drain events in order (oldest first).
741    pub fn drain_ordered(&self) -> Vec<&TraceEvent> {
742        let n = self.buffer.len();
743        if n < self.capacity || self.count <= self.capacity {
744            self.buffer.iter().collect()
745        } else {
746            let start = self.head;
747            let mut result = Vec::with_capacity(n);
748            for i in 0..n {
749                result.push(&self.buffer[(start + i) % n]);
750            }
751            result
752        }
753    }
754}
755/// A label set for a graph node.
756#[allow(dead_code)]
757pub struct LabelSet {
758    labels: Vec<String>,
759}
760#[allow(dead_code)]
761impl LabelSet {
762    /// Creates a new empty label set.
763    pub fn new() -> Self {
764        Self { labels: Vec::new() }
765    }
766    /// Adds a label (deduplicates).
767    pub fn add(&mut self, label: impl Into<String>) {
768        let s = label.into();
769        if !self.labels.contains(&s) {
770            self.labels.push(s);
771        }
772    }
773    /// Returns `true` if `label` is present.
774    pub fn has(&self, label: &str) -> bool {
775        self.labels.iter().any(|l| l == label)
776    }
777    /// Returns the count of labels.
778    pub fn count(&self) -> usize {
779        self.labels.len()
780    }
781    /// Returns all labels.
782    pub fn all(&self) -> &[String] {
783        &self.labels
784    }
785}
786/// A set of rewrite rules.
787#[allow(dead_code)]
788pub struct RewriteRuleSet {
789    rules: Vec<RewriteRule>,
790}
791#[allow(dead_code)]
792impl RewriteRuleSet {
793    /// Creates an empty rule set.
794    pub fn new() -> Self {
795        Self { rules: Vec::new() }
796    }
797    /// Adds a rule.
798    pub fn add(&mut self, rule: RewriteRule) {
799        self.rules.push(rule);
800    }
801    /// Returns the number of rules.
802    pub fn len(&self) -> usize {
803        self.rules.len()
804    }
805    /// Returns `true` if the set is empty.
806    pub fn is_empty(&self) -> bool {
807        self.rules.is_empty()
808    }
809    /// Returns all conditional rules.
810    pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
811        self.rules.iter().filter(|r| r.conditional).collect()
812    }
813    /// Returns all unconditional rules.
814    pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
815        self.rules.iter().filter(|r| !r.conditional).collect()
816    }
817    /// Looks up a rule by name.
818    pub fn get(&self, name: &str) -> Option<&RewriteRule> {
819        self.rules.iter().find(|r| r.name == name)
820    }
821}
822/// A counter that can measure elapsed time between snapshots.
823#[allow(dead_code)]
824pub struct Stopwatch {
825    start: std::time::Instant,
826    splits: Vec<f64>,
827}
828#[allow(dead_code)]
829impl Stopwatch {
830    /// Creates and starts a new stopwatch.
831    pub fn start() -> Self {
832        Self {
833            start: std::time::Instant::now(),
834            splits: Vec::new(),
835        }
836    }
837    /// Records a split time (elapsed since start).
838    pub fn split(&mut self) {
839        self.splits.push(self.elapsed_ms());
840    }
841    /// Returns total elapsed milliseconds since start.
842    pub fn elapsed_ms(&self) -> f64 {
843        self.start.elapsed().as_secs_f64() * 1000.0
844    }
845    /// Returns all recorded split times.
846    pub fn splits(&self) -> &[f64] {
847        &self.splits
848    }
849    /// Returns the number of splits.
850    pub fn num_splits(&self) -> usize {
851        self.splits.len()
852    }
853}
854/// Category of trace event.
855#[derive(Debug, Clone, PartialEq, Eq)]
856pub enum TraceCategory {
857    /// Kernel type inference.
858    Infer,
859    /// Definitional equality checking.
860    DefEq,
861    /// Reduction / normalization.
862    Reduce,
863    /// Unification.
864    Unify,
865    /// Tactic execution.
866    Tactic,
867    /// Elaboration.
868    Elab,
869    /// Typeclass resolution.
870    Typeclass,
871    /// Simp tactic.
872    Simp,
873    /// User-defined category.
874    Custom(String),
875}
876/// A sparse vector: stores only non-default elements.
877#[allow(dead_code)]
878pub struct SparseVec<T: Default + Clone + PartialEq> {
879    entries: std::collections::HashMap<usize, T>,
880    default_: T,
881    logical_len: usize,
882}
883#[allow(dead_code)]
884impl<T: Default + Clone + PartialEq> SparseVec<T> {
885    /// Creates a new sparse vector with logical length `len`.
886    pub fn new(len: usize) -> Self {
887        Self {
888            entries: std::collections::HashMap::new(),
889            default_: T::default(),
890            logical_len: len,
891        }
892    }
893    /// Sets element at `idx`.
894    pub fn set(&mut self, idx: usize, val: T) {
895        if val == self.default_ {
896            self.entries.remove(&idx);
897        } else {
898            self.entries.insert(idx, val);
899        }
900    }
901    /// Gets element at `idx`.
902    pub fn get(&self, idx: usize) -> &T {
903        self.entries.get(&idx).unwrap_or(&self.default_)
904    }
905    /// Returns the logical length.
906    pub fn len(&self) -> usize {
907        self.logical_len
908    }
909    /// Returns whether the collection is empty.
910    pub fn is_empty(&self) -> bool {
911        self.len() == 0
912    }
913    /// Returns the number of non-default elements.
914    pub fn nnz(&self) -> usize {
915        self.entries.len()
916    }
917}
918/// A reusable scratch buffer for path computations.
919#[allow(dead_code)]
920pub struct PathBuf {
921    components: Vec<String>,
922}
923#[allow(dead_code)]
924impl PathBuf {
925    /// Creates a new empty path buffer.
926    pub fn new() -> Self {
927        Self {
928            components: Vec::new(),
929        }
930    }
931    /// Pushes a component.
932    pub fn push(&mut self, comp: impl Into<String>) {
933        self.components.push(comp.into());
934    }
935    /// Pops the last component.
936    pub fn pop(&mut self) {
937        self.components.pop();
938    }
939    /// Returns the current path as a `/`-separated string.
940    pub fn as_str(&self) -> String {
941        self.components.join("/")
942    }
943    /// Returns the depth of the path.
944    pub fn depth(&self) -> usize {
945        self.components.len()
946    }
947    /// Clears the path.
948    pub fn clear(&mut self) {
949        self.components.clear();
950    }
951}
952/// A dependency closure builder (transitive closure via BFS).
953#[allow(dead_code)]
954pub struct TransitiveClosure {
955    adj: Vec<Vec<usize>>,
956    n: usize,
957}
958#[allow(dead_code)]
959impl TransitiveClosure {
960    /// Creates a transitive closure builder for `n` nodes.
961    pub fn new(n: usize) -> Self {
962        Self {
963            adj: vec![Vec::new(); n],
964            n,
965        }
966    }
967    /// Adds a direct edge.
968    pub fn add_edge(&mut self, from: usize, to: usize) {
969        if from < self.n {
970            self.adj[from].push(to);
971        }
972    }
973    /// Computes all nodes reachable from `start` (including `start`).
974    pub fn reachable_from(&self, start: usize) -> Vec<usize> {
975        let mut visited = vec![false; self.n];
976        let mut queue = std::collections::VecDeque::new();
977        queue.push_back(start);
978        while let Some(node) = queue.pop_front() {
979            if node >= self.n || visited[node] {
980                continue;
981            }
982            visited[node] = true;
983            for &next in &self.adj[node] {
984                queue.push_back(next);
985            }
986        }
987        (0..self.n).filter(|&i| visited[i]).collect()
988    }
989    /// Returns `true` if `from` can transitively reach `to`.
990    pub fn can_reach(&self, from: usize, to: usize) -> bool {
991        self.reachable_from(from).contains(&to)
992    }
993}
994/// A simple decision tree node for rule dispatching.
995#[allow(dead_code)]
996#[allow(missing_docs)]
997pub enum DecisionNode {
998    /// A leaf with an action string.
999    Leaf(String),
1000    /// An interior node: check `key` equals `val` → `yes_branch`, else `no_branch`.
1001    Branch {
1002        key: String,
1003        val: String,
1004        yes_branch: Box<DecisionNode>,
1005        no_branch: Box<DecisionNode>,
1006    },
1007}
1008#[allow(dead_code)]
1009impl DecisionNode {
1010    /// Evaluates the decision tree with the given context.
1011    pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
1012        match self {
1013            DecisionNode::Leaf(action) => action.as_str(),
1014            DecisionNode::Branch {
1015                key,
1016                val,
1017                yes_branch,
1018                no_branch,
1019            } => {
1020                let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
1021                if actual == val.as_str() {
1022                    yes_branch.evaluate(ctx)
1023                } else {
1024                    no_branch.evaluate(ctx)
1025                }
1026            }
1027        }
1028    }
1029    /// Returns the depth of the decision tree.
1030    pub fn depth(&self) -> usize {
1031        match self {
1032            DecisionNode::Leaf(_) => 0,
1033            DecisionNode::Branch {
1034                yes_branch,
1035                no_branch,
1036                ..
1037            } => 1 + yes_branch.depth().max(no_branch.depth()),
1038        }
1039    }
1040}
1041/// A tracer that also forwards events to a callback.
1042pub struct ForwardingTracer<F: FnMut(&TraceEvent)> {
1043    inner: Tracer,
1044    callback: F,
1045}
1046impl<F: FnMut(&TraceEvent)> ForwardingTracer<F> {
1047    /// Create a new forwarding tracer.
1048    pub fn new(level: TraceLevel, callback: F) -> Self {
1049        Self {
1050            inner: Tracer::new(level),
1051            callback,
1052        }
1053    }
1054    /// Log an event (forwarding to callback as well).
1055    pub fn log(&mut self, event: TraceEvent) {
1056        (self.callback)(&event);
1057        self.inner.log(event);
1058    }
1059    /// Get events.
1060    pub fn events(&self) -> &[TraceEvent] {
1061        self.inner.events()
1062    }
1063}
1064/// A hierarchical configuration tree.
1065#[allow(dead_code)]
1066pub struct ConfigNode {
1067    key: String,
1068    value: Option<String>,
1069    children: Vec<ConfigNode>,
1070}
1071#[allow(dead_code)]
1072impl ConfigNode {
1073    /// Creates a leaf config node with a value.
1074    pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
1075        Self {
1076            key: key.into(),
1077            value: Some(value.into()),
1078            children: Vec::new(),
1079        }
1080    }
1081    /// Creates a section node with children.
1082    pub fn section(key: impl Into<String>) -> Self {
1083        Self {
1084            key: key.into(),
1085            value: None,
1086            children: Vec::new(),
1087        }
1088    }
1089    /// Adds a child node.
1090    pub fn add_child(&mut self, child: ConfigNode) {
1091        self.children.push(child);
1092    }
1093    /// Returns the key.
1094    pub fn key(&self) -> &str {
1095        &self.key
1096    }
1097    /// Returns the value, or `None` for section nodes.
1098    pub fn value(&self) -> Option<&str> {
1099        self.value.as_deref()
1100    }
1101    /// Returns the number of children.
1102    pub fn num_children(&self) -> usize {
1103        self.children.len()
1104    }
1105    /// Looks up a dot-separated path.
1106    pub fn lookup(&self, path: &str) -> Option<&str> {
1107        let mut parts = path.splitn(2, '.');
1108        let head = parts.next()?;
1109        let tail = parts.next();
1110        if head != self.key {
1111            return None;
1112        }
1113        match tail {
1114            None => self.value.as_deref(),
1115            Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1116        }
1117    }
1118    fn lookup_relative(&self, path: &str) -> Option<&str> {
1119        let mut parts = path.splitn(2, '.');
1120        let head = parts.next()?;
1121        let tail = parts.next();
1122        if head != self.key {
1123            return None;
1124        }
1125        match tail {
1126            None => self.value.as_deref(),
1127            Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1128        }
1129    }
1130}
1131/// A type-erased function pointer with arity tracking.
1132#[allow(dead_code)]
1133pub struct RawFnPtr {
1134    /// The raw function pointer (stored as usize for type erasure).
1135    ptr: usize,
1136    arity: usize,
1137    name: String,
1138}
1139#[allow(dead_code)]
1140impl RawFnPtr {
1141    /// Creates a new raw function pointer descriptor.
1142    pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
1143        Self {
1144            ptr,
1145            arity,
1146            name: name.into(),
1147        }
1148    }
1149    /// Returns the arity.
1150    pub fn arity(&self) -> usize {
1151        self.arity
1152    }
1153    /// Returns the name.
1154    pub fn name(&self) -> &str {
1155        &self.name
1156    }
1157    /// Returns the raw pointer value.
1158    pub fn raw(&self) -> usize {
1159        self.ptr
1160    }
1161}
1162/// A pool of reusable string buffers.
1163#[allow(dead_code)]
1164pub struct StringPool {
1165    free: Vec<String>,
1166}
1167#[allow(dead_code)]
1168impl StringPool {
1169    /// Creates a new empty string pool.
1170    pub fn new() -> Self {
1171        Self { free: Vec::new() }
1172    }
1173    /// Takes a string from the pool (may be empty).
1174    pub fn take(&mut self) -> String {
1175        self.free.pop().unwrap_or_default()
1176    }
1177    /// Returns a string to the pool.
1178    pub fn give(&mut self, mut s: String) {
1179        s.clear();
1180        self.free.push(s);
1181    }
1182    /// Returns the number of free strings in the pool.
1183    pub fn free_count(&self) -> usize {
1184        self.free.len()
1185    }
1186}
1187/// Kind of reduction rule.
1188#[derive(Debug, Clone, PartialEq, Eq)]
1189pub enum ReductionRule {
1190    /// Beta reduction.
1191    Beta,
1192    /// Delta reduction (definition unfolding).
1193    Delta,
1194    /// Iota reduction (recursion / match).
1195    Iota,
1196    /// Zeta reduction (let unfolding).
1197    Zeta,
1198    /// Eta reduction.
1199    Eta,
1200    /// Quotient reduction.
1201    Quot,
1202}
1203/// A single trace event during type checking or elaboration.
1204#[derive(Debug, Clone)]
1205pub struct TraceEvent {
1206    /// Severity / verbosity level.
1207    pub level: TraceLevel,
1208    /// Human-readable message.
1209    pub message: String,
1210    /// Expression associated with this event.
1211    pub expr: Option<Expr>,
1212    /// Location string.
1213    pub location: String,
1214    /// Category.
1215    pub category: Option<TraceCategory>,
1216    /// Depth in the type-checking stack.
1217    pub depth: u32,
1218}
1219impl TraceEvent {
1220    /// Create a minimal trace event.
1221    pub fn new(level: TraceLevel, message: String) -> Self {
1222        Self {
1223            level,
1224            message,
1225            expr: None,
1226            location: String::new(),
1227            category: None,
1228            depth: 0,
1229        }
1230    }
1231    /// Attach an expression.
1232    pub fn with_expr(mut self, expr: Expr) -> Self {
1233        self.expr = Some(expr);
1234        self
1235    }
1236    /// Set the location.
1237    pub fn with_location(mut self, location: impl Into<String>) -> Self {
1238        self.location = location.into();
1239        self
1240    }
1241    /// Set the category.
1242    pub fn with_category(mut self, category: TraceCategory) -> Self {
1243        self.category = Some(category);
1244        self
1245    }
1246    /// Set the depth.
1247    pub fn with_depth(mut self, depth: u32) -> Self {
1248        self.depth = depth;
1249        self
1250    }
1251    /// Format as a log line.
1252    pub fn format(&self) -> String {
1253        let cat = self
1254            .category
1255            .as_ref()
1256            .map(|c| format!("[{c}] "))
1257            .unwrap_or_default();
1258        let loc = if self.location.is_empty() {
1259            String::new()
1260        } else {
1261            format!(" ({})", self.location)
1262        };
1263        let indent = "  ".repeat(self.depth as usize);
1264        format!("{}{} {}{}{}", indent, self.level, cat, self.message, loc)
1265    }
1266}
1267/// A write-once cell.
1268#[allow(dead_code)]
1269pub struct WriteOnce<T> {
1270    value: std::cell::Cell<Option<T>>,
1271}
1272#[allow(dead_code)]
1273impl<T: Copy> WriteOnce<T> {
1274    /// Creates an empty write-once cell.
1275    pub fn new() -> Self {
1276        Self {
1277            value: std::cell::Cell::new(None),
1278        }
1279    }
1280    /// Writes a value.  Returns `false` if already written.
1281    pub fn write(&self, val: T) -> bool {
1282        if self.value.get().is_some() {
1283            return false;
1284        }
1285        self.value.set(Some(val));
1286        true
1287    }
1288    /// Returns the value if written.
1289    pub fn read(&self) -> Option<T> {
1290        self.value.get()
1291    }
1292    /// Returns `true` if the value has been written.
1293    pub fn is_written(&self) -> bool {
1294        self.value.get().is_some()
1295    }
1296}
1297/// A simple directed acyclic graph.
1298#[allow(dead_code)]
1299pub struct SimpleDag {
1300    /// `edges[i]` is the list of direct successors of node `i`.
1301    edges: Vec<Vec<usize>>,
1302}
1303#[allow(dead_code)]
1304impl SimpleDag {
1305    /// Creates a DAG with `n` nodes and no edges.
1306    pub fn new(n: usize) -> Self {
1307        Self {
1308            edges: vec![Vec::new(); n],
1309        }
1310    }
1311    /// Adds an edge from `from` to `to`.
1312    pub fn add_edge(&mut self, from: usize, to: usize) {
1313        if from < self.edges.len() {
1314            self.edges[from].push(to);
1315        }
1316    }
1317    /// Returns the successors of `node`.
1318    pub fn successors(&self, node: usize) -> &[usize] {
1319        self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
1320    }
1321    /// Returns `true` if `from` can reach `to` via DFS.
1322    pub fn can_reach(&self, from: usize, to: usize) -> bool {
1323        let mut visited = vec![false; self.edges.len()];
1324        self.dfs(from, to, &mut visited)
1325    }
1326    fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
1327        if cur == target {
1328            return true;
1329        }
1330        if cur >= visited.len() || visited[cur] {
1331            return false;
1332        }
1333        visited[cur] = true;
1334        for &next in self.successors(cur) {
1335            if self.dfs(next, target, visited) {
1336                return true;
1337            }
1338        }
1339        false
1340    }
1341    /// Returns the topological order of nodes, or `None` if a cycle is detected.
1342    pub fn topological_sort(&self) -> Option<Vec<usize>> {
1343        let n = self.edges.len();
1344        let mut in_degree = vec![0usize; n];
1345        for succs in &self.edges {
1346            for &s in succs {
1347                if s < n {
1348                    in_degree[s] += 1;
1349                }
1350            }
1351        }
1352        let mut queue: std::collections::VecDeque<usize> =
1353            (0..n).filter(|&i| in_degree[i] == 0).collect();
1354        let mut order = Vec::new();
1355        while let Some(node) = queue.pop_front() {
1356            order.push(node);
1357            for &s in self.successors(node) {
1358                if s < n {
1359                    in_degree[s] -= 1;
1360                    if in_degree[s] == 0 {
1361                        queue.push_back(s);
1362                    }
1363                }
1364            }
1365        }
1366        if order.len() == n {
1367            Some(order)
1368        } else {
1369            None
1370        }
1371    }
1372    /// Returns the number of nodes.
1373    pub fn num_nodes(&self) -> usize {
1374        self.edges.len()
1375    }
1376}
1377/// A generic counter that tracks min/max/sum for statistical summaries.
1378#[allow(dead_code)]
1379pub struct StatSummary {
1380    count: u64,
1381    sum: f64,
1382    min: f64,
1383    max: f64,
1384}
1385#[allow(dead_code)]
1386impl StatSummary {
1387    /// Creates an empty summary.
1388    pub fn new() -> Self {
1389        Self {
1390            count: 0,
1391            sum: 0.0,
1392            min: f64::INFINITY,
1393            max: f64::NEG_INFINITY,
1394        }
1395    }
1396    /// Records a sample.
1397    pub fn record(&mut self, val: f64) {
1398        self.count += 1;
1399        self.sum += val;
1400        if val < self.min {
1401            self.min = val;
1402        }
1403        if val > self.max {
1404            self.max = val;
1405        }
1406    }
1407    /// Returns the mean, or `None` if no samples.
1408    pub fn mean(&self) -> Option<f64> {
1409        if self.count == 0 {
1410            None
1411        } else {
1412            Some(self.sum / self.count as f64)
1413        }
1414    }
1415    /// Returns the minimum, or `None` if no samples.
1416    pub fn min(&self) -> Option<f64> {
1417        if self.count == 0 {
1418            None
1419        } else {
1420            Some(self.min)
1421        }
1422    }
1423    /// Returns the maximum, or `None` if no samples.
1424    pub fn max(&self) -> Option<f64> {
1425        if self.count == 0 {
1426            None
1427        } else {
1428            Some(self.max)
1429        }
1430    }
1431    /// Returns the count of recorded samples.
1432    pub fn count(&self) -> u64 {
1433        self.count
1434    }
1435}
1436/// Trace level for filtering output.
1437#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
1438pub enum TraceLevel {
1439    /// No tracing.
1440    Off,
1441    /// Fatal errors only.
1442    Error,
1443    /// Warnings and errors.
1444    Warn,
1445    /// Informational messages.
1446    Info,
1447    /// Verbose debugging.
1448    Debug,
1449    /// Everything including internal details.
1450    Trace,
1451}
1452impl TraceLevel {
1453    /// Parse from a string.
1454    #[allow(clippy::should_implement_trait)]
1455    pub fn from_str(s: &str) -> Option<Self> {
1456        match s.to_lowercase().as_str() {
1457            "off" => Some(TraceLevel::Off),
1458            "error" => Some(TraceLevel::Error),
1459            "warn" | "warning" => Some(TraceLevel::Warn),
1460            "info" => Some(TraceLevel::Info),
1461            "debug" => Some(TraceLevel::Debug),
1462            "trace" => Some(TraceLevel::Trace),
1463            _ => None,
1464        }
1465    }
1466    /// Check whether at least as verbose as other.
1467    pub fn is_at_least(&self, other: TraceLevel) -> bool {
1468        *self >= other
1469    }
1470}
1471/// Aggregate statistics about a Tracer's events.
1472#[derive(Debug, Default, Clone)]
1473pub struct TracerStats {
1474    /// Total events logged.
1475    pub total: usize,
1476    /// Events at Error level.
1477    pub errors: usize,
1478    /// Events at Warn level.
1479    pub warnings: usize,
1480    /// Events at Info level.
1481    pub infos: usize,
1482    /// Events at Debug level.
1483    pub debugs: usize,
1484    /// Events at Trace level.
1485    pub traces: usize,
1486}
1487impl TracerStats {
1488    /// Compute stats for a tracer.
1489    pub fn compute(tracer: &Tracer) -> Self {
1490        let mut stats = Self {
1491            total: tracer.event_count(),
1492            ..Default::default()
1493        };
1494        for event in tracer.events() {
1495            match event.level {
1496                TraceLevel::Error => stats.errors += 1,
1497                TraceLevel::Warn => stats.warnings += 1,
1498                TraceLevel::Info => stats.infos += 1,
1499                TraceLevel::Debug => stats.debugs += 1,
1500                TraceLevel::Trace => stats.traces += 1,
1501                TraceLevel::Off => {}
1502            }
1503        }
1504        stats
1505    }
1506    /// Check whether any errors were logged.
1507    pub fn has_errors(&self) -> bool {
1508        self.errors > 0
1509    }
1510    /// Check whether any warnings were logged.
1511    pub fn has_warnings(&self) -> bool {
1512        self.warnings > 0
1513    }
1514}
1515/// A simple key-value store backed by a sorted Vec for small maps.
1516#[allow(dead_code)]
1517pub struct SmallMap<K: Ord + Clone, V: Clone> {
1518    entries: Vec<(K, V)>,
1519}
1520#[allow(dead_code)]
1521impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
1522    /// Creates a new empty small map.
1523    pub fn new() -> Self {
1524        Self {
1525            entries: Vec::new(),
1526        }
1527    }
1528    /// Inserts or replaces the value for `key`.
1529    pub fn insert(&mut self, key: K, val: V) {
1530        match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
1531            Ok(i) => self.entries[i].1 = val,
1532            Err(i) => self.entries.insert(i, (key, val)),
1533        }
1534    }
1535    /// Returns the value for `key`, or `None`.
1536    pub fn get(&self, key: &K) -> Option<&V> {
1537        self.entries
1538            .binary_search_by_key(&key, |(k, _)| k)
1539            .ok()
1540            .map(|i| &self.entries[i].1)
1541    }
1542    /// Returns the number of entries.
1543    pub fn len(&self) -> usize {
1544        self.entries.len()
1545    }
1546    /// Returns `true` if empty.
1547    pub fn is_empty(&self) -> bool {
1548        self.entries.is_empty()
1549    }
1550    /// Returns all keys.
1551    pub fn keys(&self) -> Vec<&K> {
1552        self.entries.iter().map(|(k, _)| k).collect()
1553    }
1554    /// Returns all values.
1555    pub fn values(&self) -> Vec<&V> {
1556        self.entries.iter().map(|(_, v)| v).collect()
1557    }
1558}
1559/// A tagged union for representing a simple two-case discriminated union.
1560#[allow(dead_code)]
1561pub enum Either2<A, B> {
1562    /// The first alternative.
1563    First(A),
1564    /// The second alternative.
1565    Second(B),
1566}
1567#[allow(dead_code)]
1568impl<A, B> Either2<A, B> {
1569    /// Returns `true` if this is the first alternative.
1570    pub fn is_first(&self) -> bool {
1571        matches!(self, Either2::First(_))
1572    }
1573    /// Returns `true` if this is the second alternative.
1574    pub fn is_second(&self) -> bool {
1575        matches!(self, Either2::Second(_))
1576    }
1577    /// Returns the first value if present.
1578    pub fn first(self) -> Option<A> {
1579        match self {
1580            Either2::First(a) => Some(a),
1581            _ => None,
1582        }
1583    }
1584    /// Returns the second value if present.
1585    pub fn second(self) -> Option<B> {
1586        match self {
1587            Either2::Second(b) => Some(b),
1588            _ => None,
1589        }
1590    }
1591    /// Maps over the first alternative.
1592    pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
1593        match self {
1594            Either2::First(a) => Either2::First(f(a)),
1595            Either2::Second(b) => Either2::Second(b),
1596        }
1597    }
1598}
1599/// A token bucket rate limiter.
1600#[allow(dead_code)]
1601pub struct TokenBucket {
1602    capacity: u64,
1603    tokens: u64,
1604    refill_per_ms: u64,
1605    last_refill: std::time::Instant,
1606}
1607#[allow(dead_code)]
1608impl TokenBucket {
1609    /// Creates a new token bucket.
1610    pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
1611        Self {
1612            capacity,
1613            tokens: capacity,
1614            refill_per_ms,
1615            last_refill: std::time::Instant::now(),
1616        }
1617    }
1618    /// Attempts to consume `n` tokens.  Returns `true` on success.
1619    pub fn try_consume(&mut self, n: u64) -> bool {
1620        self.refill();
1621        if self.tokens >= n {
1622            self.tokens -= n;
1623            true
1624        } else {
1625            false
1626        }
1627    }
1628    fn refill(&mut self) {
1629        let now = std::time::Instant::now();
1630        let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
1631        if elapsed_ms > 0 {
1632            let new_tokens = elapsed_ms * self.refill_per_ms;
1633            self.tokens = (self.tokens + new_tokens).min(self.capacity);
1634            self.last_refill = now;
1635        }
1636    }
1637    /// Returns the number of currently available tokens.
1638    pub fn available(&self) -> u64 {
1639        self.tokens
1640    }
1641    /// Returns the bucket capacity.
1642    pub fn capacity(&self) -> u64 {
1643        self.capacity
1644    }
1645}
1646/// A simple log sink that writes to a `Vec<String>`.
1647#[derive(Default, Debug, Clone)]
1648pub struct StringSink {
1649    pub(crate) lines: Vec<String>,
1650}
1651impl StringSink {
1652    /// Create an empty sink.
1653    pub fn new() -> Self {
1654        Self { lines: Vec::new() }
1655    }
1656    /// Record a formatted event.
1657    pub fn record(&mut self, event: &TraceEvent) {
1658        self.lines.push(event.format());
1659    }
1660    /// Get all recorded lines.
1661    pub fn lines(&self) -> &[String] {
1662        &self.lines
1663    }
1664    /// Clear all lines.
1665    pub fn clear(&mut self) {
1666        self.lines.clear();
1667    }
1668    /// Number of recorded lines.
1669    pub fn len(&self) -> usize {
1670        self.lines.len()
1671    }
1672    /// Check if empty.
1673    pub fn is_empty(&self) -> bool {
1674        self.lines.is_empty()
1675    }
1676    /// Render to a single string with newlines.
1677    pub fn render(&self) -> String {
1678        self.lines.join("\n")
1679    }
1680}