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