1use crate::wall_clock::Instant;
6use crate::Expr;
7use std::time::Duration;
8
9use std::collections::HashMap;
10
11#[allow(dead_code)]
13pub struct VersionedRecord<T: Clone> {
14 earlier: Vec<T>,
16 current: T,
18}
19#[allow(dead_code)]
20impl<T: Clone> VersionedRecord<T> {
21 pub fn new(initial: T) -> Self {
23 Self {
24 earlier: Vec::new(),
25 current: initial,
26 }
27 }
28 pub fn update(&mut self, val: T) {
30 let previous = std::mem::replace(&mut self.current, val);
31 self.earlier.push(previous);
32 }
33 pub fn current(&self) -> &T {
35 &self.current
36 }
37 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 pub fn version(&self) -> usize {
47 self.earlier.len()
48 }
49 pub fn has_history(&self) -> bool {
51 !self.earlier.is_empty()
52 }
53}
54#[allow(dead_code)]
56pub struct TransformStat {
57 before: StatSummary,
58 after: StatSummary,
59}
60#[allow(dead_code)]
61impl TransformStat {
62 pub fn new() -> Self {
64 Self {
65 before: StatSummary::new(),
66 after: StatSummary::new(),
67 }
68 }
69 pub fn record_before(&mut self, v: f64) {
71 self.before.record(v);
72 }
73 pub fn record_after(&mut self, v: f64) {
75 self.after.record(v);
76 }
77 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}
87pub 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 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 pub fn silent() -> Self {
114 Self::new(TraceLevel::Off)
115 }
116 pub fn verbose() -> Self {
118 Self::new(TraceLevel::Trace)
119 }
120 pub fn set_level(&mut self, level: TraceLevel) {
122 self.level = level;
123 }
124 pub fn level(&self) -> TraceLevel {
126 self.level
127 }
128 pub fn set_max_events(&mut self, max: usize) {
130 self.max_events = max;
131 }
132 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 pub fn suppress(&mut self, cat: TraceCategory) {
139 if !self.suppressed_categories.contains(&cat) {
140 self.suppressed_categories.push(cat);
141 }
142 }
143 pub fn allow(&mut self, cat: &TraceCategory) {
145 self.suppressed_categories.retain(|c| c != cat);
146 }
147 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 pub fn log_msg(&mut self, level: TraceLevel, msg: impl Into<String>) {
165 self.log(TraceEvent::new(level, msg.into()));
166 }
167 pub fn error(&mut self, msg: impl Into<String>) {
169 self.log_msg(TraceLevel::Error, msg);
170 }
171 pub fn warn(&mut self, msg: impl Into<String>) {
173 self.log_msg(TraceLevel::Warn, msg);
174 }
175 pub fn info(&mut self, msg: impl Into<String>) {
177 self.log_msg(TraceLevel::Info, msg);
178 }
179 pub fn debug(&mut self, msg: impl Into<String>) {
181 self.log_msg(TraceLevel::Debug, msg);
182 }
183 pub fn trace_msg(&mut self, msg: impl Into<String>) {
185 self.log_msg(TraceLevel::Trace, msg);
186 }
187 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 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 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 pub fn reduction_steps(&self) -> &[ReductionStep] {
211 &self.reduction_steps
212 }
213 pub fn clear_reductions(&mut self) {
215 self.reduction_steps.clear();
216 }
217 pub fn events(&self) -> &[TraceEvent] {
219 &self.events
220 }
221 pub fn events_at_level(&self, level: TraceLevel) -> Vec<&TraceEvent> {
223 self.events.iter().filter(|e| e.level <= level).collect()
224 }
225 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 pub fn clear(&mut self) {
234 self.events.clear();
235 }
236 pub fn event_count(&self) -> usize {
238 self.events.len()
239 }
240 pub fn push(&mut self) {
242 self.depth += 1;
243 }
244 pub fn pop(&mut self) {
246 if self.depth > 0 {
247 self.depth -= 1;
248 }
249 }
250 pub fn current_depth(&self) -> u32 {
252 self.depth
253 }
254 pub fn elapsed(&self) -> Option<Duration> {
256 self.start_time.map(|t| t.elapsed())
257 }
258 pub fn render(&self) -> String {
260 self.events
261 .iter()
262 .map(|e| e.format())
263 .collect::<Vec<_>>()
264 .join("\n")
265 }
266}
267impl Tracer {
269 pub fn debug_return<T>(&mut self, value: T, msg: impl Into<String>) -> T {
271 self.debug(msg);
272 value
273 }
274 pub fn debug_expr(&mut self, label: &str, expr: &Expr) {
276 self.debug(format!("{}: {:?}", label, expr));
277 }
278 pub fn stats(&self) -> TracerStats {
280 TracerStats::compute(self)
281 }
282 pub fn last_event(&self) -> Option<&TraceEvent> {
284 self.events().last()
285 }
286 pub fn last_error(&self) -> Option<&TraceEvent> {
288 self.events()
289 .iter()
290 .rev()
291 .find(|e| e.level == TraceLevel::Error)
292 }
293 pub fn is_empty(&self) -> bool {
295 self.events().is_empty()
296 }
297 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 pub fn log_infer(&mut self, msg: impl Into<String>) {
308 self.log_with_category(TraceLevel::Debug, TraceCategory::Infer, msg);
309 }
310 pub fn log_simp(&mut self, msg: impl Into<String>) {
312 self.log_with_category(TraceLevel::Trace, TraceCategory::Simp, msg);
313 }
314 pub fn log_tactic(&mut self, msg: impl Into<String>) {
316 self.log_with_category(TraceLevel::Info, TraceCategory::Tactic, msg);
317 }
318 pub fn log_elab(&mut self, msg: impl Into<String>) {
320 self.log_with_category(TraceLevel::Debug, TraceCategory::Elab, msg);
321 }
322 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 pub fn clear_category(&mut self, cat: &TraceCategory) {
331 self.info(format!("[cleared category {}]", cat));
332 }
333}
334#[allow(dead_code)]
336#[allow(missing_docs)]
337pub struct RewriteRule {
338 pub name: String,
340 pub lhs: String,
342 pub rhs: String,
344 pub conditional: bool,
346}
347#[allow(dead_code)]
348impl RewriteRule {
349 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 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 pub fn display(&self) -> String {
377 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
378 }
379}
380#[allow(dead_code)]
382pub struct StackCalc {
383 stack: Vec<i64>,
384}
385#[allow(dead_code)]
386impl StackCalc {
387 pub fn new() -> Self {
389 Self { stack: Vec::new() }
390 }
391 pub fn push(&mut self, n: i64) {
393 self.stack.push(n);
394 }
395 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 pub fn add(&mut self) -> Option<i64> {
412 self.apply_binary(|a, b| a + b)
413 }
414 pub fn sub(&mut self) -> Option<i64> {
418 self.apply_binary(|a, b| a - b)
419 }
420 pub fn mul(&mut self) -> Option<i64> {
424 self.apply_binary(|a, b| a * b)
425 }
426 pub fn peek(&self) -> Option<i64> {
428 self.stack.last().copied()
429 }
430 pub fn depth(&self) -> usize {
432 self.stack.len()
433 }
434}
435pub struct TraceSpan<'a> {
437 pub(crate) tracer: &'a mut Tracer,
438 pub(crate) name: &'static str,
439}
440impl<'a> TraceSpan<'a> {
441 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 pub fn log(&mut self, msg: impl Into<String>) {
449 self.tracer.info(msg);
450 }
451 pub fn close(self) {}
453}
454#[allow(dead_code)]
456pub struct FocusStack<T> {
457 items: Vec<T>,
458}
459#[allow(dead_code)]
460impl<T> FocusStack<T> {
461 pub fn new() -> Self {
463 Self { items: Vec::new() }
464 }
465 pub fn focus(&mut self, item: T) {
467 self.items.push(item);
468 }
469 pub fn blur(&mut self) -> Option<T> {
471 self.items.pop()
472 }
473 pub fn current(&self) -> Option<&T> {
475 self.items.last()
476 }
477 pub fn depth(&self) -> usize {
479 self.items.len()
480 }
481 pub fn is_empty(&self) -> bool {
483 self.items.is_empty()
484 }
485}
486#[allow(dead_code)]
488pub struct NonEmptyVec<T> {
489 head: T,
490 tail: Vec<T>,
491}
492#[allow(dead_code)]
493impl<T> NonEmptyVec<T> {
494 pub fn singleton(val: T) -> Self {
496 Self {
497 head: val,
498 tail: Vec::new(),
499 }
500 }
501 pub fn push(&mut self, val: T) {
503 self.tail.push(val);
504 }
505 pub fn first(&self) -> &T {
507 &self.head
508 }
509 pub fn last(&self) -> &T {
511 self.tail.last().unwrap_or(&self.head)
512 }
513 pub fn len(&self) -> usize {
515 1 + self.tail.len()
516 }
517 pub fn is_empty(&self) -> bool {
519 self.len() == 0
520 }
521 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#[allow(dead_code)]
530pub struct FlatSubstitution {
531 pairs: Vec<(String, String)>,
532}
533#[allow(dead_code)]
534impl FlatSubstitution {
535 pub fn new() -> Self {
537 Self { pairs: Vec::new() }
538 }
539 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
541 self.pairs.push((from.into(), to.into()));
542 }
543 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 pub fn len(&self) -> usize {
553 self.pairs.len()
554 }
555 pub fn is_empty(&self) -> bool {
557 self.pairs.is_empty()
558 }
559}
560#[derive(Clone, Debug)]
562pub struct TraceFilter {
563 pub min_level: TraceLevel,
565 pub categories: Option<Vec<TraceCategory>>,
567 pub exclude_text: Option<String>,
569}
570impl TraceFilter {
571 pub fn at_level(level: TraceLevel) -> Self {
573 Self {
574 min_level: level,
575 categories: None,
576 exclude_text: None,
577 }
578 }
579 pub fn with_categories(mut self, cats: Vec<TraceCategory>) -> Self {
581 self.categories = Some(cats);
582 self
583 }
584 pub fn excluding(mut self, text: impl Into<String>) -> Self {
586 self.exclude_text = Some(text.into());
587 self
588 }
589 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#[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 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 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 pub fn sum(&self) -> f64 {
650 self.sum
651 }
652 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 pub fn count(&self) -> usize {
662 self.count
663 }
664}
665#[derive(Debug, Clone)]
667pub struct ReductionStep {
668 pub rule: ReductionRule,
670 pub before: Expr,
672 pub after: Expr,
674}
675#[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 pub fn new(data: &'a [T], window: usize) -> Self {
686 Self {
687 data,
688 pos: 0,
689 window,
690 }
691 }
692}
693pub struct RingTracer {
695 buffer: Vec<TraceEvent>,
696 capacity: usize,
697 head: usize,
698 count: usize,
699 level: TraceLevel,
700}
701impl RingTracer {
702 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 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 pub fn log_msg(&mut self, level: TraceLevel, msg: impl Into<String>) {
727 self.log(TraceEvent::new(level, msg.into()));
728 }
729 pub fn stored_count(&self) -> usize {
731 self.buffer.len()
732 }
733 pub fn total_count(&self) -> usize {
735 self.count
736 }
737 pub fn clear(&mut self) {
739 self.buffer.clear();
740 self.head = 0;
741 self.count = 0;
742 }
743 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#[allow(dead_code)]
760pub struct LabelSet {
761 labels: Vec<String>,
762}
763#[allow(dead_code)]
764impl LabelSet {
765 pub fn new() -> Self {
767 Self { labels: Vec::new() }
768 }
769 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 pub fn has(&self, label: &str) -> bool {
778 self.labels.iter().any(|l| l == label)
779 }
780 pub fn count(&self) -> usize {
782 self.labels.len()
783 }
784 pub fn all(&self) -> &[String] {
786 &self.labels
787 }
788}
789#[allow(dead_code)]
791pub struct RewriteRuleSet {
792 rules: Vec<RewriteRule>,
793}
794#[allow(dead_code)]
795impl RewriteRuleSet {
796 pub fn new() -> Self {
798 Self { rules: Vec::new() }
799 }
800 pub fn add(&mut self, rule: RewriteRule) {
802 self.rules.push(rule);
803 }
804 pub fn len(&self) -> usize {
806 self.rules.len()
807 }
808 pub fn is_empty(&self) -> bool {
810 self.rules.is_empty()
811 }
812 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
814 self.rules.iter().filter(|r| r.conditional).collect()
815 }
816 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
818 self.rules.iter().filter(|r| !r.conditional).collect()
819 }
820 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
822 self.rules.iter().find(|r| r.name == name)
823 }
824}
825#[allow(dead_code)]
827pub struct Stopwatch {
828 start: crate::wall_clock::Instant,
829 splits: Vec<f64>,
830}
831#[allow(dead_code)]
832impl Stopwatch {
833 pub fn start() -> Self {
835 Self {
836 start: crate::wall_clock::Instant::now(),
837 splits: Vec::new(),
838 }
839 }
840 pub fn split(&mut self) {
842 self.splits.push(self.elapsed_ms());
843 }
844 pub fn elapsed_ms(&self) -> f64 {
846 self.start.elapsed().as_secs_f64() * 1000.0
847 }
848 pub fn splits(&self) -> &[f64] {
850 &self.splits
851 }
852 pub fn num_splits(&self) -> usize {
854 self.splits.len()
855 }
856}
857#[derive(Debug, Clone, PartialEq, Eq)]
859pub enum TraceCategory {
860 Infer,
862 DefEq,
864 Reduce,
866 Unify,
868 Tactic,
870 Elab,
872 Typeclass,
874 Simp,
876 Custom(String),
878}
879#[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 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 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 pub fn get(&self, idx: usize) -> &T {
906 self.entries.get(&idx).unwrap_or(&self.default_)
907 }
908 pub fn len(&self) -> usize {
910 self.logical_len
911 }
912 pub fn is_empty(&self) -> bool {
914 self.len() == 0
915 }
916 pub fn nnz(&self) -> usize {
918 self.entries.len()
919 }
920}
921#[allow(dead_code)]
923pub struct PathBuf {
924 components: Vec<String>,
925}
926#[allow(dead_code)]
927impl PathBuf {
928 pub fn new() -> Self {
930 Self {
931 components: Vec::new(),
932 }
933 }
934 pub fn push(&mut self, comp: impl Into<String>) {
936 self.components.push(comp.into());
937 }
938 pub fn pop(&mut self) {
940 self.components.pop();
941 }
942 pub fn as_str(&self) -> String {
944 self.components.join("/")
945 }
946 pub fn depth(&self) -> usize {
948 self.components.len()
949 }
950 pub fn clear(&mut self) {
952 self.components.clear();
953 }
954}
955#[allow(dead_code)]
957pub struct TransitiveClosure {
958 adj: Vec<Vec<usize>>,
959 n: usize,
960}
961#[allow(dead_code)]
962impl TransitiveClosure {
963 pub fn new(n: usize) -> Self {
965 Self {
966 adj: vec![Vec::new(); n],
967 n,
968 }
969 }
970 pub fn add_edge(&mut self, from: usize, to: usize) {
972 if from < self.n {
973 self.adj[from].push(to);
974 }
975 }
976 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 pub fn can_reach(&self, from: usize, to: usize) -> bool {
994 self.reachable_from(from).contains(&to)
995 }
996}
997#[allow(dead_code)]
999#[allow(missing_docs)]
1000pub enum DecisionNode {
1001 Leaf(String),
1003 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 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 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}
1044pub struct ForwardingTracer<F: FnMut(&TraceEvent)> {
1046 inner: Tracer,
1047 callback: F,
1048}
1049impl<F: FnMut(&TraceEvent)> ForwardingTracer<F> {
1050 pub fn new(level: TraceLevel, callback: F) -> Self {
1052 Self {
1053 inner: Tracer::new(level),
1054 callback,
1055 }
1056 }
1057 pub fn log(&mut self, event: TraceEvent) {
1059 (self.callback)(&event);
1060 self.inner.log(event);
1061 }
1062 pub fn events(&self) -> &[TraceEvent] {
1064 self.inner.events()
1065 }
1066}
1067#[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 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 pub fn section(key: impl Into<String>) -> Self {
1086 Self {
1087 key: key.into(),
1088 value: None,
1089 children: Vec::new(),
1090 }
1091 }
1092 pub fn add_child(&mut self, child: ConfigNode) {
1094 self.children.push(child);
1095 }
1096 pub fn key(&self) -> &str {
1098 &self.key
1099 }
1100 pub fn value(&self) -> Option<&str> {
1102 self.value.as_deref()
1103 }
1104 pub fn num_children(&self) -> usize {
1106 self.children.len()
1107 }
1108 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#[allow(dead_code)]
1136pub struct RawFnPtr {
1137 ptr: usize,
1139 arity: usize,
1140 name: String,
1141}
1142#[allow(dead_code)]
1143impl RawFnPtr {
1144 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 pub fn arity(&self) -> usize {
1154 self.arity
1155 }
1156 pub fn name(&self) -> &str {
1158 &self.name
1159 }
1160 pub fn raw(&self) -> usize {
1162 self.ptr
1163 }
1164}
1165#[allow(dead_code)]
1167pub struct StringPool {
1168 free: Vec<String>,
1169}
1170#[allow(dead_code)]
1171impl StringPool {
1172 pub fn new() -> Self {
1174 Self { free: Vec::new() }
1175 }
1176 pub fn take(&mut self) -> String {
1178 self.free.pop().unwrap_or_default()
1179 }
1180 pub fn give(&mut self, mut s: String) {
1182 s.clear();
1183 self.free.push(s);
1184 }
1185 pub fn free_count(&self) -> usize {
1187 self.free.len()
1188 }
1189}
1190#[derive(Debug, Clone, PartialEq, Eq)]
1192pub enum ReductionRule {
1193 Beta,
1195 Delta,
1197 Iota,
1199 Zeta,
1201 Eta,
1203 Quot,
1205}
1206#[derive(Debug, Clone)]
1208pub struct TraceEvent {
1209 pub level: TraceLevel,
1211 pub message: String,
1213 pub expr: Option<Expr>,
1215 pub location: String,
1217 pub category: Option<TraceCategory>,
1219 pub depth: u32,
1221}
1222impl TraceEvent {
1223 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 pub fn with_expr(mut self, expr: Expr) -> Self {
1236 self.expr = Some(expr);
1237 self
1238 }
1239 pub fn with_location(mut self, location: impl Into<String>) -> Self {
1241 self.location = location.into();
1242 self
1243 }
1244 pub fn with_category(mut self, category: TraceCategory) -> Self {
1246 self.category = Some(category);
1247 self
1248 }
1249 pub fn with_depth(mut self, depth: u32) -> Self {
1251 self.depth = depth;
1252 self
1253 }
1254 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#[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 pub fn new() -> Self {
1279 Self {
1280 value: std::cell::Cell::new(None),
1281 }
1282 }
1283 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 pub fn read(&self) -> Option<T> {
1293 self.value.get()
1294 }
1295 pub fn is_written(&self) -> bool {
1297 self.value.get().is_some()
1298 }
1299}
1300#[allow(dead_code)]
1302pub struct SimpleDag {
1303 edges: Vec<Vec<usize>>,
1305}
1306#[allow(dead_code)]
1307impl SimpleDag {
1308 pub fn new(n: usize) -> Self {
1310 Self {
1311 edges: vec![Vec::new(); n],
1312 }
1313 }
1314 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 pub fn successors(&self, node: usize) -> &[usize] {
1322 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
1323 }
1324 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 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 pub fn num_nodes(&self) -> usize {
1377 self.edges.len()
1378 }
1379}
1380#[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 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 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 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 pub fn min(&self) -> Option<f64> {
1420 if self.count == 0 {
1421 None
1422 } else {
1423 Some(self.min)
1424 }
1425 }
1426 pub fn max(&self) -> Option<f64> {
1428 if self.count == 0 {
1429 None
1430 } else {
1431 Some(self.max)
1432 }
1433 }
1434 pub fn count(&self) -> u64 {
1436 self.count
1437 }
1438}
1439#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
1441pub enum TraceLevel {
1442 Off,
1444 Error,
1446 Warn,
1448 Info,
1450 Debug,
1452 Trace,
1454}
1455impl TraceLevel {
1456 #[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 pub fn is_at_least(&self, other: TraceLevel) -> bool {
1471 *self >= other
1472 }
1473}
1474#[derive(Debug, Default, Clone)]
1476pub struct TracerStats {
1477 pub total: usize,
1479 pub errors: usize,
1481 pub warnings: usize,
1483 pub infos: usize,
1485 pub debugs: usize,
1487 pub traces: usize,
1489}
1490impl TracerStats {
1491 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 pub fn has_errors(&self) -> bool {
1511 self.errors > 0
1512 }
1513 pub fn has_warnings(&self) -> bool {
1515 self.warnings > 0
1516 }
1517}
1518#[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 pub fn new() -> Self {
1527 Self {
1528 entries: Vec::new(),
1529 }
1530 }
1531 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 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 pub fn len(&self) -> usize {
1547 self.entries.len()
1548 }
1549 pub fn is_empty(&self) -> bool {
1551 self.entries.is_empty()
1552 }
1553 pub fn keys(&self) -> Vec<&K> {
1555 self.entries.iter().map(|(k, _)| k).collect()
1556 }
1557 pub fn values(&self) -> Vec<&V> {
1559 self.entries.iter().map(|(_, v)| v).collect()
1560 }
1561}
1562#[allow(dead_code)]
1564pub enum Either2<A, B> {
1565 First(A),
1567 Second(B),
1569}
1570#[allow(dead_code)]
1571impl<A, B> Either2<A, B> {
1572 pub fn is_first(&self) -> bool {
1574 matches!(self, Either2::First(_))
1575 }
1576 pub fn is_second(&self) -> bool {
1578 matches!(self, Either2::Second(_))
1579 }
1580 pub fn first(self) -> Option<A> {
1582 match self {
1583 Either2::First(a) => Some(a),
1584 _ => None,
1585 }
1586 }
1587 pub fn second(self) -> Option<B> {
1589 match self {
1590 Either2::Second(b) => Some(b),
1591 _ => None,
1592 }
1593 }
1594 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#[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 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 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 pub fn available(&self) -> u64 {
1642 self.tokens
1643 }
1644 pub fn capacity(&self) -> u64 {
1646 self.capacity
1647 }
1648}
1649#[derive(Default, Debug, Clone)]
1651pub struct StringSink {
1652 pub(crate) lines: Vec<String>,
1653}
1654impl StringSink {
1655 pub fn new() -> Self {
1657 Self { lines: Vec::new() }
1658 }
1659 pub fn record(&mut self, event: &TraceEvent) {
1661 self.lines.push(event.format());
1662 }
1663 pub fn lines(&self) -> &[String] {
1665 &self.lines
1666 }
1667 pub fn clear(&mut self) {
1669 self.lines.clear();
1670 }
1671 pub fn len(&self) -> usize {
1673 self.lines.len()
1674 }
1675 pub fn is_empty(&self) -> bool {
1677 self.lines.is_empty()
1678 }
1679 pub fn render(&self) -> String {
1681 self.lines.join("\n")
1682 }
1683}