1use crate::Expr;
6use std::time::{Duration, Instant};
7
8use std::collections::HashMap;
9
10#[allow(dead_code)]
12pub struct VersionedRecord<T: Clone> {
13 history: Vec<T>,
14}
15#[allow(dead_code)]
16impl<T: Clone> VersionedRecord<T> {
17 pub fn new(initial: T) -> Self {
19 Self {
20 history: vec![initial],
21 }
22 }
23 pub fn update(&mut self, val: T) {
25 self.history.push(val);
26 }
27 pub fn current(&self) -> &T {
29 self.history
30 .last()
31 .expect("VersionedRecord history is always non-empty after construction")
32 }
33 pub fn at_version(&self, n: usize) -> Option<&T> {
35 self.history.get(n)
36 }
37 pub fn version(&self) -> usize {
39 self.history.len() - 1
40 }
41 pub fn has_history(&self) -> bool {
43 self.history.len() > 1
44 }
45}
46#[allow(dead_code)]
48pub struct TransformStat {
49 before: StatSummary,
50 after: StatSummary,
51}
52#[allow(dead_code)]
53impl TransformStat {
54 pub fn new() -> Self {
56 Self {
57 before: StatSummary::new(),
58 after: StatSummary::new(),
59 }
60 }
61 pub fn record_before(&mut self, v: f64) {
63 self.before.record(v);
64 }
65 pub fn record_after(&mut self, v: f64) {
67 self.after.record(v);
68 }
69 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}
79pub 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 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 pub fn silent() -> Self {
106 Self::new(TraceLevel::Off)
107 }
108 pub fn verbose() -> Self {
110 Self::new(TraceLevel::Trace)
111 }
112 pub fn set_level(&mut self, level: TraceLevel) {
114 self.level = level;
115 }
116 pub fn level(&self) -> TraceLevel {
118 self.level
119 }
120 pub fn set_max_events(&mut self, max: usize) {
122 self.max_events = max;
123 }
124 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 pub fn suppress(&mut self, cat: TraceCategory) {
131 if !self.suppressed_categories.contains(&cat) {
132 self.suppressed_categories.push(cat);
133 }
134 }
135 pub fn allow(&mut self, cat: &TraceCategory) {
137 self.suppressed_categories.retain(|c| c != cat);
138 }
139 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 pub fn log_msg(&mut self, level: TraceLevel, msg: impl Into<String>) {
157 self.log(TraceEvent::new(level, msg.into()));
158 }
159 pub fn error(&mut self, msg: impl Into<String>) {
161 self.log_msg(TraceLevel::Error, msg);
162 }
163 pub fn warn(&mut self, msg: impl Into<String>) {
165 self.log_msg(TraceLevel::Warn, msg);
166 }
167 pub fn info(&mut self, msg: impl Into<String>) {
169 self.log_msg(TraceLevel::Info, msg);
170 }
171 pub fn debug(&mut self, msg: impl Into<String>) {
173 self.log_msg(TraceLevel::Debug, msg);
174 }
175 pub fn trace_msg(&mut self, msg: impl Into<String>) {
177 self.log_msg(TraceLevel::Trace, msg);
178 }
179 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 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 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 pub fn reduction_steps(&self) -> &[ReductionStep] {
203 &self.reduction_steps
204 }
205 pub fn clear_reductions(&mut self) {
207 self.reduction_steps.clear();
208 }
209 pub fn events(&self) -> &[TraceEvent] {
211 &self.events
212 }
213 pub fn events_at_level(&self, level: TraceLevel) -> Vec<&TraceEvent> {
215 self.events.iter().filter(|e| e.level <= level).collect()
216 }
217 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 pub fn clear(&mut self) {
226 self.events.clear();
227 }
228 pub fn event_count(&self) -> usize {
230 self.events.len()
231 }
232 pub fn push(&mut self) {
234 self.depth += 1;
235 }
236 pub fn pop(&mut self) {
238 if self.depth > 0 {
239 self.depth -= 1;
240 }
241 }
242 pub fn current_depth(&self) -> u32 {
244 self.depth
245 }
246 pub fn elapsed(&self) -> Option<Duration> {
248 self.start_time.map(|t| t.elapsed())
249 }
250 pub fn render(&self) -> String {
252 self.events
253 .iter()
254 .map(|e| e.format())
255 .collect::<Vec<_>>()
256 .join("\n")
257 }
258}
259impl Tracer {
261 pub fn debug_return<T>(&mut self, value: T, msg: impl Into<String>) -> T {
263 self.debug(msg);
264 value
265 }
266 pub fn debug_expr(&mut self, label: &str, expr: &Expr) {
268 self.debug(format!("{}: {:?}", label, expr));
269 }
270 pub fn stats(&self) -> TracerStats {
272 TracerStats::compute(self)
273 }
274 pub fn last_event(&self) -> Option<&TraceEvent> {
276 self.events().last()
277 }
278 pub fn last_error(&self) -> Option<&TraceEvent> {
280 self.events()
281 .iter()
282 .rev()
283 .find(|e| e.level == TraceLevel::Error)
284 }
285 pub fn is_empty(&self) -> bool {
287 self.events().is_empty()
288 }
289 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 pub fn log_infer(&mut self, msg: impl Into<String>) {
300 self.log_with_category(TraceLevel::Debug, TraceCategory::Infer, msg);
301 }
302 pub fn log_simp(&mut self, msg: impl Into<String>) {
304 self.log_with_category(TraceLevel::Trace, TraceCategory::Simp, msg);
305 }
306 pub fn log_tactic(&mut self, msg: impl Into<String>) {
308 self.log_with_category(TraceLevel::Info, TraceCategory::Tactic, msg);
309 }
310 pub fn log_elab(&mut self, msg: impl Into<String>) {
312 self.log_with_category(TraceLevel::Debug, TraceCategory::Elab, msg);
313 }
314 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 pub fn clear_category(&mut self, cat: &TraceCategory) {
323 self.info(format!("[cleared category {}]", cat));
324 }
325}
326#[allow(dead_code)]
328#[allow(missing_docs)]
329pub struct RewriteRule {
330 pub name: String,
332 pub lhs: String,
334 pub rhs: String,
336 pub conditional: bool,
338}
339#[allow(dead_code)]
340impl RewriteRule {
341 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 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 pub fn display(&self) -> String {
369 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
370 }
371}
372#[allow(dead_code)]
374pub struct StackCalc {
375 stack: Vec<i64>,
376}
377#[allow(dead_code)]
378impl StackCalc {
379 pub fn new() -> Self {
381 Self { stack: Vec::new() }
382 }
383 pub fn push(&mut self, n: i64) {
385 self.stack.push(n);
386 }
387 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 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 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 pub fn peek(&self) -> Option<i64> {
425 self.stack.last().copied()
426 }
427 pub fn depth(&self) -> usize {
429 self.stack.len()
430 }
431}
432pub struct TraceSpan<'a> {
434 pub(crate) tracer: &'a mut Tracer,
435 pub(crate) name: &'static str,
436}
437impl<'a> TraceSpan<'a> {
438 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 pub fn log(&mut self, msg: impl Into<String>) {
446 self.tracer.info(msg);
447 }
448 pub fn close(self) {}
450}
451#[allow(dead_code)]
453pub struct FocusStack<T> {
454 items: Vec<T>,
455}
456#[allow(dead_code)]
457impl<T> FocusStack<T> {
458 pub fn new() -> Self {
460 Self { items: Vec::new() }
461 }
462 pub fn focus(&mut self, item: T) {
464 self.items.push(item);
465 }
466 pub fn blur(&mut self) -> Option<T> {
468 self.items.pop()
469 }
470 pub fn current(&self) -> Option<&T> {
472 self.items.last()
473 }
474 pub fn depth(&self) -> usize {
476 self.items.len()
477 }
478 pub fn is_empty(&self) -> bool {
480 self.items.is_empty()
481 }
482}
483#[allow(dead_code)]
485pub struct NonEmptyVec<T> {
486 head: T,
487 tail: Vec<T>,
488}
489#[allow(dead_code)]
490impl<T> NonEmptyVec<T> {
491 pub fn singleton(val: T) -> Self {
493 Self {
494 head: val,
495 tail: Vec::new(),
496 }
497 }
498 pub fn push(&mut self, val: T) {
500 self.tail.push(val);
501 }
502 pub fn first(&self) -> &T {
504 &self.head
505 }
506 pub fn last(&self) -> &T {
508 self.tail.last().unwrap_or(&self.head)
509 }
510 pub fn len(&self) -> usize {
512 1 + self.tail.len()
513 }
514 pub fn is_empty(&self) -> bool {
516 self.len() == 0
517 }
518 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#[allow(dead_code)]
527pub struct FlatSubstitution {
528 pairs: Vec<(String, String)>,
529}
530#[allow(dead_code)]
531impl FlatSubstitution {
532 pub fn new() -> Self {
534 Self { pairs: Vec::new() }
535 }
536 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
538 self.pairs.push((from.into(), to.into()));
539 }
540 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 pub fn len(&self) -> usize {
550 self.pairs.len()
551 }
552 pub fn is_empty(&self) -> bool {
554 self.pairs.is_empty()
555 }
556}
557#[derive(Clone, Debug)]
559pub struct TraceFilter {
560 pub min_level: TraceLevel,
562 pub categories: Option<Vec<TraceCategory>>,
564 pub exclude_text: Option<String>,
566}
567impl TraceFilter {
568 pub fn at_level(level: TraceLevel) -> Self {
570 Self {
571 min_level: level,
572 categories: None,
573 exclude_text: None,
574 }
575 }
576 pub fn with_categories(mut self, cats: Vec<TraceCategory>) -> Self {
578 self.categories = Some(cats);
579 self
580 }
581 pub fn excluding(mut self, text: impl Into<String>) -> Self {
583 self.exclude_text = Some(text.into());
584 self
585 }
586 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#[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 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 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 pub fn sum(&self) -> f64 {
647 self.sum
648 }
649 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 pub fn count(&self) -> usize {
659 self.count
660 }
661}
662#[derive(Debug, Clone)]
664pub struct ReductionStep {
665 pub rule: ReductionRule,
667 pub before: Expr,
669 pub after: Expr,
671}
672#[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 pub fn new(data: &'a [T], window: usize) -> Self {
683 Self {
684 data,
685 pos: 0,
686 window,
687 }
688 }
689}
690pub struct RingTracer {
692 buffer: Vec<TraceEvent>,
693 capacity: usize,
694 head: usize,
695 count: usize,
696 level: TraceLevel,
697}
698impl RingTracer {
699 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 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 pub fn log_msg(&mut self, level: TraceLevel, msg: impl Into<String>) {
724 self.log(TraceEvent::new(level, msg.into()));
725 }
726 pub fn stored_count(&self) -> usize {
728 self.buffer.len()
729 }
730 pub fn total_count(&self) -> usize {
732 self.count
733 }
734 pub fn clear(&mut self) {
736 self.buffer.clear();
737 self.head = 0;
738 self.count = 0;
739 }
740 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#[allow(dead_code)]
757pub struct LabelSet {
758 labels: Vec<String>,
759}
760#[allow(dead_code)]
761impl LabelSet {
762 pub fn new() -> Self {
764 Self { labels: Vec::new() }
765 }
766 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 pub fn has(&self, label: &str) -> bool {
775 self.labels.iter().any(|l| l == label)
776 }
777 pub fn count(&self) -> usize {
779 self.labels.len()
780 }
781 pub fn all(&self) -> &[String] {
783 &self.labels
784 }
785}
786#[allow(dead_code)]
788pub struct RewriteRuleSet {
789 rules: Vec<RewriteRule>,
790}
791#[allow(dead_code)]
792impl RewriteRuleSet {
793 pub fn new() -> Self {
795 Self { rules: Vec::new() }
796 }
797 pub fn add(&mut self, rule: RewriteRule) {
799 self.rules.push(rule);
800 }
801 pub fn len(&self) -> usize {
803 self.rules.len()
804 }
805 pub fn is_empty(&self) -> bool {
807 self.rules.is_empty()
808 }
809 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
811 self.rules.iter().filter(|r| r.conditional).collect()
812 }
813 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
815 self.rules.iter().filter(|r| !r.conditional).collect()
816 }
817 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
819 self.rules.iter().find(|r| r.name == name)
820 }
821}
822#[allow(dead_code)]
824pub struct Stopwatch {
825 start: std::time::Instant,
826 splits: Vec<f64>,
827}
828#[allow(dead_code)]
829impl Stopwatch {
830 pub fn start() -> Self {
832 Self {
833 start: std::time::Instant::now(),
834 splits: Vec::new(),
835 }
836 }
837 pub fn split(&mut self) {
839 self.splits.push(self.elapsed_ms());
840 }
841 pub fn elapsed_ms(&self) -> f64 {
843 self.start.elapsed().as_secs_f64() * 1000.0
844 }
845 pub fn splits(&self) -> &[f64] {
847 &self.splits
848 }
849 pub fn num_splits(&self) -> usize {
851 self.splits.len()
852 }
853}
854#[derive(Debug, Clone, PartialEq, Eq)]
856pub enum TraceCategory {
857 Infer,
859 DefEq,
861 Reduce,
863 Unify,
865 Tactic,
867 Elab,
869 Typeclass,
871 Simp,
873 Custom(String),
875}
876#[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 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 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 pub fn get(&self, idx: usize) -> &T {
903 self.entries.get(&idx).unwrap_or(&self.default_)
904 }
905 pub fn len(&self) -> usize {
907 self.logical_len
908 }
909 pub fn is_empty(&self) -> bool {
911 self.len() == 0
912 }
913 pub fn nnz(&self) -> usize {
915 self.entries.len()
916 }
917}
918#[allow(dead_code)]
920pub struct PathBuf {
921 components: Vec<String>,
922}
923#[allow(dead_code)]
924impl PathBuf {
925 pub fn new() -> Self {
927 Self {
928 components: Vec::new(),
929 }
930 }
931 pub fn push(&mut self, comp: impl Into<String>) {
933 self.components.push(comp.into());
934 }
935 pub fn pop(&mut self) {
937 self.components.pop();
938 }
939 pub fn as_str(&self) -> String {
941 self.components.join("/")
942 }
943 pub fn depth(&self) -> usize {
945 self.components.len()
946 }
947 pub fn clear(&mut self) {
949 self.components.clear();
950 }
951}
952#[allow(dead_code)]
954pub struct TransitiveClosure {
955 adj: Vec<Vec<usize>>,
956 n: usize,
957}
958#[allow(dead_code)]
959impl TransitiveClosure {
960 pub fn new(n: usize) -> Self {
962 Self {
963 adj: vec![Vec::new(); n],
964 n,
965 }
966 }
967 pub fn add_edge(&mut self, from: usize, to: usize) {
969 if from < self.n {
970 self.adj[from].push(to);
971 }
972 }
973 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 pub fn can_reach(&self, from: usize, to: usize) -> bool {
991 self.reachable_from(from).contains(&to)
992 }
993}
994#[allow(dead_code)]
996#[allow(missing_docs)]
997pub enum DecisionNode {
998 Leaf(String),
1000 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 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 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}
1041pub struct ForwardingTracer<F: FnMut(&TraceEvent)> {
1043 inner: Tracer,
1044 callback: F,
1045}
1046impl<F: FnMut(&TraceEvent)> ForwardingTracer<F> {
1047 pub fn new(level: TraceLevel, callback: F) -> Self {
1049 Self {
1050 inner: Tracer::new(level),
1051 callback,
1052 }
1053 }
1054 pub fn log(&mut self, event: TraceEvent) {
1056 (self.callback)(&event);
1057 self.inner.log(event);
1058 }
1059 pub fn events(&self) -> &[TraceEvent] {
1061 self.inner.events()
1062 }
1063}
1064#[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 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 pub fn section(key: impl Into<String>) -> Self {
1083 Self {
1084 key: key.into(),
1085 value: None,
1086 children: Vec::new(),
1087 }
1088 }
1089 pub fn add_child(&mut self, child: ConfigNode) {
1091 self.children.push(child);
1092 }
1093 pub fn key(&self) -> &str {
1095 &self.key
1096 }
1097 pub fn value(&self) -> Option<&str> {
1099 self.value.as_deref()
1100 }
1101 pub fn num_children(&self) -> usize {
1103 self.children.len()
1104 }
1105 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#[allow(dead_code)]
1133pub struct RawFnPtr {
1134 ptr: usize,
1136 arity: usize,
1137 name: String,
1138}
1139#[allow(dead_code)]
1140impl RawFnPtr {
1141 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 pub fn arity(&self) -> usize {
1151 self.arity
1152 }
1153 pub fn name(&self) -> &str {
1155 &self.name
1156 }
1157 pub fn raw(&self) -> usize {
1159 self.ptr
1160 }
1161}
1162#[allow(dead_code)]
1164pub struct StringPool {
1165 free: Vec<String>,
1166}
1167#[allow(dead_code)]
1168impl StringPool {
1169 pub fn new() -> Self {
1171 Self { free: Vec::new() }
1172 }
1173 pub fn take(&mut self) -> String {
1175 self.free.pop().unwrap_or_default()
1176 }
1177 pub fn give(&mut self, mut s: String) {
1179 s.clear();
1180 self.free.push(s);
1181 }
1182 pub fn free_count(&self) -> usize {
1184 self.free.len()
1185 }
1186}
1187#[derive(Debug, Clone, PartialEq, Eq)]
1189pub enum ReductionRule {
1190 Beta,
1192 Delta,
1194 Iota,
1196 Zeta,
1198 Eta,
1200 Quot,
1202}
1203#[derive(Debug, Clone)]
1205pub struct TraceEvent {
1206 pub level: TraceLevel,
1208 pub message: String,
1210 pub expr: Option<Expr>,
1212 pub location: String,
1214 pub category: Option<TraceCategory>,
1216 pub depth: u32,
1218}
1219impl TraceEvent {
1220 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 pub fn with_expr(mut self, expr: Expr) -> Self {
1233 self.expr = Some(expr);
1234 self
1235 }
1236 pub fn with_location(mut self, location: impl Into<String>) -> Self {
1238 self.location = location.into();
1239 self
1240 }
1241 pub fn with_category(mut self, category: TraceCategory) -> Self {
1243 self.category = Some(category);
1244 self
1245 }
1246 pub fn with_depth(mut self, depth: u32) -> Self {
1248 self.depth = depth;
1249 self
1250 }
1251 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#[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 pub fn new() -> Self {
1276 Self {
1277 value: std::cell::Cell::new(None),
1278 }
1279 }
1280 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 pub fn read(&self) -> Option<T> {
1290 self.value.get()
1291 }
1292 pub fn is_written(&self) -> bool {
1294 self.value.get().is_some()
1295 }
1296}
1297#[allow(dead_code)]
1299pub struct SimpleDag {
1300 edges: Vec<Vec<usize>>,
1302}
1303#[allow(dead_code)]
1304impl SimpleDag {
1305 pub fn new(n: usize) -> Self {
1307 Self {
1308 edges: vec![Vec::new(); n],
1309 }
1310 }
1311 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 pub fn successors(&self, node: usize) -> &[usize] {
1319 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
1320 }
1321 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 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 pub fn num_nodes(&self) -> usize {
1374 self.edges.len()
1375 }
1376}
1377#[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 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 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 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 pub fn min(&self) -> Option<f64> {
1417 if self.count == 0 {
1418 None
1419 } else {
1420 Some(self.min)
1421 }
1422 }
1423 pub fn max(&self) -> Option<f64> {
1425 if self.count == 0 {
1426 None
1427 } else {
1428 Some(self.max)
1429 }
1430 }
1431 pub fn count(&self) -> u64 {
1433 self.count
1434 }
1435}
1436#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
1438pub enum TraceLevel {
1439 Off,
1441 Error,
1443 Warn,
1445 Info,
1447 Debug,
1449 Trace,
1451}
1452impl TraceLevel {
1453 #[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 pub fn is_at_least(&self, other: TraceLevel) -> bool {
1468 *self >= other
1469 }
1470}
1471#[derive(Debug, Default, Clone)]
1473pub struct TracerStats {
1474 pub total: usize,
1476 pub errors: usize,
1478 pub warnings: usize,
1480 pub infos: usize,
1482 pub debugs: usize,
1484 pub traces: usize,
1486}
1487impl TracerStats {
1488 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 pub fn has_errors(&self) -> bool {
1508 self.errors > 0
1509 }
1510 pub fn has_warnings(&self) -> bool {
1512 self.warnings > 0
1513 }
1514}
1515#[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 pub fn new() -> Self {
1524 Self {
1525 entries: Vec::new(),
1526 }
1527 }
1528 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 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 pub fn len(&self) -> usize {
1544 self.entries.len()
1545 }
1546 pub fn is_empty(&self) -> bool {
1548 self.entries.is_empty()
1549 }
1550 pub fn keys(&self) -> Vec<&K> {
1552 self.entries.iter().map(|(k, _)| k).collect()
1553 }
1554 pub fn values(&self) -> Vec<&V> {
1556 self.entries.iter().map(|(_, v)| v).collect()
1557 }
1558}
1559#[allow(dead_code)]
1561pub enum Either2<A, B> {
1562 First(A),
1564 Second(B),
1566}
1567#[allow(dead_code)]
1568impl<A, B> Either2<A, B> {
1569 pub fn is_first(&self) -> bool {
1571 matches!(self, Either2::First(_))
1572 }
1573 pub fn is_second(&self) -> bool {
1575 matches!(self, Either2::Second(_))
1576 }
1577 pub fn first(self) -> Option<A> {
1579 match self {
1580 Either2::First(a) => Some(a),
1581 _ => None,
1582 }
1583 }
1584 pub fn second(self) -> Option<B> {
1586 match self {
1587 Either2::Second(b) => Some(b),
1588 _ => None,
1589 }
1590 }
1591 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#[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 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 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 pub fn available(&self) -> u64 {
1639 self.tokens
1640 }
1641 pub fn capacity(&self) -> u64 {
1643 self.capacity
1644 }
1645}
1646#[derive(Default, Debug, Clone)]
1648pub struct StringSink {
1649 pub(crate) lines: Vec<String>,
1650}
1651impl StringSink {
1652 pub fn new() -> Self {
1654 Self { lines: Vec::new() }
1655 }
1656 pub fn record(&mut self, event: &TraceEvent) {
1658 self.lines.push(event.format());
1659 }
1660 pub fn lines(&self) -> &[String] {
1662 &self.lines
1663 }
1664 pub fn clear(&mut self) {
1666 self.lines.clear();
1667 }
1668 pub fn len(&self) -> usize {
1670 self.lines.len()
1671 }
1672 pub fn is_empty(&self) -> bool {
1674 self.lines.is_empty()
1675 }
1676 pub fn render(&self) -> String {
1678 self.lines.join("\n")
1679 }
1680}