1use crate::Node;
6use crate::{BinderInfo, Environment, Expr, FVarId, Level, Literal, Name, Reducer};
7use std::rc::Rc;
8
9use std::collections::HashMap;
10
11#[allow(dead_code)]
13pub struct ConfigNode {
14 key: String,
15 value: Option<String>,
16 children: Vec<ConfigNode>,
17}
18#[allow(dead_code)]
19impl ConfigNode {
20 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
22 Self {
23 key: key.into(),
24 value: Some(value.into()),
25 children: Vec::new(),
26 }
27 }
28 pub fn section(key: impl Into<String>) -> Self {
30 Self {
31 key: key.into(),
32 value: None,
33 children: Vec::new(),
34 }
35 }
36 pub fn add_child(&mut self, child: ConfigNode) {
38 self.children.push(child);
39 }
40 pub fn key(&self) -> &str {
42 &self.key
43 }
44 pub fn value(&self) -> Option<&str> {
46 self.value.as_deref()
47 }
48 pub fn num_children(&self) -> usize {
50 self.children.len()
51 }
52 pub fn lookup(&self, path: &str) -> Option<&str> {
54 let mut parts = path.splitn(2, '.');
55 let head = parts.next()?;
56 let tail = parts.next();
57 if head != self.key {
58 return None;
59 }
60 match tail {
61 None => self.value.as_deref(),
62 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
63 }
64 }
65 fn lookup_relative(&self, path: &str) -> Option<&str> {
66 let mut parts = path.splitn(2, '.');
67 let head = parts.next()?;
68 let tail = parts.next();
69 if head != self.key {
70 return None;
71 }
72 match tail {
73 None => self.value.as_deref(),
74 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
75 }
76 }
77}
78#[allow(dead_code)]
80pub struct PrefixCounter {
81 children: std::collections::HashMap<char, PrefixCounter>,
82 count: usize,
83}
84#[allow(dead_code)]
85impl PrefixCounter {
86 pub fn new() -> Self {
88 Self {
89 children: std::collections::HashMap::new(),
90 count: 0,
91 }
92 }
93 pub fn record(&mut self, s: &str) {
95 self.count += 1;
96 let mut node = self;
97 for c in s.chars() {
98 node = node.children.entry(c).or_default();
99 node.count += 1;
100 }
101 }
102 pub fn count_with_prefix(&self, prefix: &str) -> usize {
104 let mut node = self;
105 for c in prefix.chars() {
106 match node.children.get(&c) {
107 Some(n) => node = n,
108 None => return 0,
109 }
110 }
111 node.count
112 }
113}
114#[allow(dead_code)]
116pub struct FlatSubstitution {
117 pairs: Vec<(String, String)>,
118}
119#[allow(dead_code)]
120impl FlatSubstitution {
121 pub fn new() -> Self {
123 Self { pairs: Vec::new() }
124 }
125 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
127 self.pairs.push((from.into(), to.into()));
128 }
129 pub fn apply(&self, s: &str) -> String {
131 let mut result = s.to_string();
132 for (from, to) in &self.pairs {
133 result = result.replace(from.as_str(), to.as_str());
134 }
135 result
136 }
137 pub fn len(&self) -> usize {
139 self.pairs.len()
140 }
141 pub fn is_empty(&self) -> bool {
143 self.pairs.is_empty()
144 }
145}
146#[allow(dead_code)]
148pub struct VersionedRecord<T: Clone> {
149 earlier: Vec<T>,
151 current: T,
153}
154#[allow(dead_code)]
155impl<T: Clone> VersionedRecord<T> {
156 pub fn new(initial: T) -> Self {
158 Self {
159 earlier: Vec::new(),
160 current: initial,
161 }
162 }
163 pub fn update(&mut self, val: T) {
165 let previous = std::mem::replace(&mut self.current, val);
166 self.earlier.push(previous);
167 }
168 pub fn current(&self) -> &T {
170 &self.current
171 }
172 pub fn at_version(&self, n: usize) -> Option<&T> {
174 match self.earlier.get(n) {
175 Some(value) => Some(value),
176 None if n == self.earlier.len() => Some(&self.current),
177 None => None,
178 }
179 }
180 pub fn version(&self) -> usize {
182 self.earlier.len()
183 }
184 pub fn has_history(&self) -> bool {
186 !self.earlier.is_empty()
187 }
188}
189#[allow(dead_code)]
191pub struct WindowIterator<'a, T> {
192 pub(super) data: &'a [T],
193 pub(super) pos: usize,
194 pub(super) window: usize,
195}
196#[allow(dead_code)]
197impl<'a, T> WindowIterator<'a, T> {
198 pub fn new(data: &'a [T], window: usize) -> Self {
200 Self {
201 data,
202 pos: 0,
203 window,
204 }
205 }
206}
207#[allow(dead_code)]
209pub struct MinHeap<T: Ord> {
210 data: Vec<T>,
211}
212#[allow(dead_code)]
213impl<T: Ord> MinHeap<T> {
214 pub fn new() -> Self {
216 Self { data: Vec::new() }
217 }
218 pub fn push(&mut self, val: T) {
220 self.data.push(val);
221 self.sift_up(self.data.len() - 1);
222 }
223 pub fn pop(&mut self) -> Option<T> {
225 if self.data.is_empty() {
226 return None;
227 }
228 let n = self.data.len();
229 self.data.swap(0, n - 1);
230 let min = self.data.pop();
231 if !self.data.is_empty() {
232 self.sift_down(0);
233 }
234 min
235 }
236 pub fn peek(&self) -> Option<&T> {
238 self.data.first()
239 }
240 pub fn len(&self) -> usize {
242 self.data.len()
243 }
244 pub fn is_empty(&self) -> bool {
246 self.data.is_empty()
247 }
248 fn sift_up(&mut self, mut i: usize) {
249 while i > 0 {
250 let parent = (i - 1) / 2;
251 if self.data[i] < self.data[parent] {
252 self.data.swap(i, parent);
253 i = parent;
254 } else {
255 break;
256 }
257 }
258 }
259 fn sift_down(&mut self, mut i: usize) {
260 let n = self.data.len();
261 loop {
262 let left = 2 * i + 1;
263 let right = 2 * i + 2;
264 let mut smallest = i;
265 if left < n && self.data[left] < self.data[smallest] {
266 smallest = left;
267 }
268 if right < n && self.data[right] < self.data[smallest] {
269 smallest = right;
270 }
271 if smallest == i {
272 break;
273 }
274 self.data.swap(i, smallest);
275 i = smallest;
276 }
277 }
278}
279#[derive(Clone, Debug, Default)]
281pub struct WhnfStats {
282 pub beta_steps: u64,
284 pub delta_steps: u64,
286 pub zeta_steps: u64,
288 pub iota_steps: u64,
290 pub total_exprs: u64,
292}
293impl WhnfStats {
294 pub fn new() -> Self {
296 Self::default()
297 }
298 pub fn total_steps(&self) -> u64 {
300 self.beta_steps + self.delta_steps + self.zeta_steps + self.iota_steps
301 }
302 pub fn any_progress(&self) -> bool {
304 self.total_steps() > 0
305 }
306}
307#[allow(dead_code)]
309pub struct StackCalc {
310 stack: Vec<i64>,
311}
312#[allow(dead_code)]
313impl StackCalc {
314 pub fn new() -> Self {
316 Self { stack: Vec::new() }
317 }
318 pub fn push(&mut self, n: i64) {
320 self.stack.push(n);
321 }
322 fn apply_binary(&mut self, op: impl FnOnce(i64, i64) -> i64) -> Option<i64> {
326 let (rest_len, a, b) = match self.stack[..] {
327 [ref rest @ .., a, b] => (rest.len(), a, b),
328 _ => return None,
329 };
330 let value = op(a, b);
331 self.stack.truncate(rest_len);
332 self.stack.push(value);
333 Some(value)
334 }
335 pub fn add(&mut self) -> Option<i64> {
339 self.apply_binary(|a, b| a + b)
340 }
341 pub fn sub(&mut self) -> Option<i64> {
345 self.apply_binary(|a, b| a - b)
346 }
347 pub fn mul(&mut self) -> Option<i64> {
351 self.apply_binary(|a, b| a * b)
352 }
353 pub fn peek(&self) -> Option<i64> {
355 self.stack.last().copied()
356 }
357 pub fn depth(&self) -> usize {
359 self.stack.len()
360 }
361}
362#[allow(dead_code)]
364pub struct FocusStack<T> {
365 items: Vec<T>,
366}
367#[allow(dead_code)]
368impl<T> FocusStack<T> {
369 pub fn new() -> Self {
371 Self { items: Vec::new() }
372 }
373 pub fn focus(&mut self, item: T) {
375 self.items.push(item);
376 }
377 pub fn blur(&mut self) -> Option<T> {
379 self.items.pop()
380 }
381 pub fn current(&self) -> Option<&T> {
383 self.items.last()
384 }
385 pub fn depth(&self) -> usize {
387 self.items.len()
388 }
389 pub fn is_empty(&self) -> bool {
391 self.items.is_empty()
392 }
393}
394#[derive(Clone, Copy, Debug, PartialEq, Eq)]
396pub struct ReductionBudget {
397 pub remaining: u64,
399}
400impl ReductionBudget {
401 pub fn new(n: u64) -> Self {
403 Self { remaining: n }
404 }
405 pub fn unlimited() -> Self {
407 Self {
408 remaining: u64::MAX,
409 }
410 }
411 pub fn consume(&mut self) -> bool {
413 if self.remaining == 0 {
414 return false;
415 }
416 self.remaining -= 1;
417 true
418 }
419 pub fn is_active(&self) -> bool {
421 self.remaining > 0
422 }
423}
424#[allow(dead_code)]
426pub struct TransformStat {
427 before: StatSummary,
428 after: StatSummary,
429}
430#[allow(dead_code)]
431impl TransformStat {
432 pub fn new() -> Self {
434 Self {
435 before: StatSummary::new(),
436 after: StatSummary::new(),
437 }
438 }
439 pub fn record_before(&mut self, v: f64) {
441 self.before.record(v);
442 }
443 pub fn record_after(&mut self, v: f64) {
445 self.after.record(v);
446 }
447 pub fn mean_ratio(&self) -> Option<f64> {
449 let b = self.before.mean()?;
450 let a = self.after.mean()?;
451 if b.abs() < f64::EPSILON {
452 return None;
453 }
454 Some(a / b)
455 }
456}
457#[allow(dead_code)]
459pub struct SimpleDag {
460 edges: Vec<Vec<usize>>,
462}
463#[allow(dead_code)]
464impl SimpleDag {
465 pub fn new(n: usize) -> Self {
467 Self {
468 edges: vec![Vec::new(); n],
469 }
470 }
471 pub fn add_edge(&mut self, from: usize, to: usize) {
473 if from < self.edges.len() {
474 self.edges[from].push(to);
475 }
476 }
477 pub fn successors(&self, node: usize) -> &[usize] {
479 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
480 }
481 pub fn can_reach(&self, from: usize, to: usize) -> bool {
483 let mut visited = vec![false; self.edges.len()];
484 self.dfs(from, to, &mut visited)
485 }
486 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
487 if cur == target {
488 return true;
489 }
490 if cur >= visited.len() || visited[cur] {
491 return false;
492 }
493 visited[cur] = true;
494 for &next in self.successors(cur) {
495 if self.dfs(next, target, visited) {
496 return true;
497 }
498 }
499 false
500 }
501 pub fn topological_sort(&self) -> Option<Vec<usize>> {
503 let n = self.edges.len();
504 let mut in_degree = vec![0usize; n];
505 for succs in &self.edges {
506 for &s in succs {
507 if s < n {
508 in_degree[s] += 1;
509 }
510 }
511 }
512 let mut queue: std::collections::VecDeque<usize> =
513 (0..n).filter(|&i| in_degree[i] == 0).collect();
514 let mut order = Vec::new();
515 while let Some(node) = queue.pop_front() {
516 order.push(node);
517 for &s in self.successors(node) {
518 if s < n {
519 in_degree[s] -= 1;
520 if in_degree[s] == 0 {
521 queue.push_back(s);
522 }
523 }
524 }
525 }
526 if order.len() == n {
527 Some(order)
528 } else {
529 None
530 }
531 }
532 pub fn num_nodes(&self) -> usize {
534 self.edges.len()
535 }
536}
537#[derive(Clone, Debug)]
539pub struct WhnfDepthBudget {
540 pub budget: u32,
542 pub remaining: u32,
544}
545impl WhnfDepthBudget {
546 pub fn new(budget: u32) -> Self {
548 Self {
549 budget,
550 remaining: budget,
551 }
552 }
553 pub fn unlimited() -> Self {
555 Self {
556 budget: u32::MAX,
557 remaining: u32::MAX,
558 }
559 }
560 pub fn consume(&mut self) -> bool {
562 if self.remaining > 0 {
563 self.remaining -= 1;
564 true
565 } else {
566 false
567 }
568 }
569 pub fn is_exhausted(&self) -> bool {
571 self.remaining == 0
572 }
573 pub fn consumed(&self) -> u32 {
575 self.budget.saturating_sub(self.remaining)
576 }
577 pub fn reset(&mut self) {
579 self.remaining = self.budget;
580 }
581}
582#[derive(Clone, Debug, PartialEq, Eq)]
584pub enum StuckReason {
585 FreeVariable(FVarId),
587 OpaqueConst(Name),
589 NormalForm,
591}
592#[allow(dead_code)]
594pub struct SmallMap<K: Ord + Clone, V: Clone> {
595 entries: Vec<(K, V)>,
596}
597#[allow(dead_code)]
598impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
599 pub fn new() -> Self {
601 Self {
602 entries: Vec::new(),
603 }
604 }
605 pub fn insert(&mut self, key: K, val: V) {
607 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
608 Ok(i) => self.entries[i].1 = val,
609 Err(i) => self.entries.insert(i, (key, val)),
610 }
611 }
612 pub fn get(&self, key: &K) -> Option<&V> {
614 self.entries
615 .binary_search_by_key(&key, |(k, _)| k)
616 .ok()
617 .map(|i| &self.entries[i].1)
618 }
619 pub fn len(&self) -> usize {
621 self.entries.len()
622 }
623 pub fn is_empty(&self) -> bool {
625 self.entries.is_empty()
626 }
627 pub fn keys(&self) -> Vec<&K> {
629 self.entries.iter().map(|(k, _)| k).collect()
630 }
631 pub fn values(&self) -> Vec<&V> {
633 self.entries.iter().map(|(_, v)| v).collect()
634 }
635}
636#[allow(dead_code)]
638pub struct StatSummary {
639 count: u64,
640 sum: f64,
641 min: f64,
642 max: f64,
643}
644#[allow(dead_code)]
645impl StatSummary {
646 pub fn new() -> Self {
648 Self {
649 count: 0,
650 sum: 0.0,
651 min: f64::INFINITY,
652 max: f64::NEG_INFINITY,
653 }
654 }
655 pub fn record(&mut self, val: f64) {
657 self.count += 1;
658 self.sum += val;
659 if val < self.min {
660 self.min = val;
661 }
662 if val > self.max {
663 self.max = val;
664 }
665 }
666 pub fn mean(&self) -> Option<f64> {
668 if self.count == 0 {
669 None
670 } else {
671 Some(self.sum / self.count as f64)
672 }
673 }
674 pub fn min(&self) -> Option<f64> {
676 if self.count == 0 {
677 None
678 } else {
679 Some(self.min)
680 }
681 }
682 pub fn max(&self) -> Option<f64> {
684 if self.count == 0 {
685 None
686 } else {
687 Some(self.max)
688 }
689 }
690 pub fn count(&self) -> u64 {
692 self.count
693 }
694}
695#[allow(dead_code)]
697pub struct PathBuf {
698 components: Vec<String>,
699}
700#[allow(dead_code)]
701impl PathBuf {
702 pub fn new() -> Self {
704 Self {
705 components: Vec::new(),
706 }
707 }
708 pub fn push(&mut self, comp: impl Into<String>) {
710 self.components.push(comp.into());
711 }
712 pub fn pop(&mut self) {
714 self.components.pop();
715 }
716 pub fn as_str(&self) -> String {
718 self.components.join("/")
719 }
720 pub fn depth(&self) -> usize {
722 self.components.len()
723 }
724 pub fn clear(&mut self) {
726 self.components.clear();
727 }
728}
729#[allow(dead_code)]
731pub struct TransitiveClosure {
732 adj: Vec<Vec<usize>>,
733 n: usize,
734}
735#[allow(dead_code)]
736impl TransitiveClosure {
737 pub fn new(n: usize) -> Self {
739 Self {
740 adj: vec![Vec::new(); n],
741 n,
742 }
743 }
744 pub fn add_edge(&mut self, from: usize, to: usize) {
746 if from < self.n {
747 self.adj[from].push(to);
748 }
749 }
750 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
752 let mut visited = vec![false; self.n];
753 let mut queue = std::collections::VecDeque::new();
754 queue.push_back(start);
755 while let Some(node) = queue.pop_front() {
756 if node >= self.n || visited[node] {
757 continue;
758 }
759 visited[node] = true;
760 for &next in &self.adj[node] {
761 queue.push_back(next);
762 }
763 }
764 (0..self.n).filter(|&i| visited[i]).collect()
765 }
766 pub fn can_reach(&self, from: usize, to: usize) -> bool {
768 self.reachable_from(from).contains(&to)
769 }
770}
771#[allow(dead_code)]
773pub struct RewriteRuleSet {
774 rules: Vec<RewriteRule>,
775}
776#[allow(dead_code)]
777impl RewriteRuleSet {
778 pub fn new() -> Self {
780 Self { rules: Vec::new() }
781 }
782 pub fn add(&mut self, rule: RewriteRule) {
784 self.rules.push(rule);
785 }
786 pub fn len(&self) -> usize {
788 self.rules.len()
789 }
790 pub fn is_empty(&self) -> bool {
792 self.rules.is_empty()
793 }
794 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
796 self.rules.iter().filter(|r| r.conditional).collect()
797 }
798 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
800 self.rules.iter().filter(|r| !r.conditional).collect()
801 }
802 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
804 self.rules.iter().find(|r| r.name == name)
805 }
806}
807#[derive(Clone, Copy, Debug, PartialEq, Eq)]
809pub enum WhnfReductionOrder {
810 BetaFirst,
812 DeltaFirst,
814 StructuralOnly,
816}
817#[allow(dead_code)]
819pub struct Stopwatch {
820 start: crate::wall_clock::Instant,
821 splits: Vec<f64>,
822}
823#[allow(dead_code)]
824impl Stopwatch {
825 pub fn start() -> Self {
827 Self {
828 start: crate::wall_clock::Instant::now(),
829 splits: Vec::new(),
830 }
831 }
832 pub fn split(&mut self) {
834 self.splits.push(self.elapsed_ms());
835 }
836 pub fn elapsed_ms(&self) -> f64 {
838 self.start.elapsed().as_secs_f64() * 1000.0
839 }
840 pub fn splits(&self) -> &[f64] {
842 &self.splits
843 }
844 pub fn num_splits(&self) -> usize {
846 self.splits.len()
847 }
848}
849#[allow(dead_code)]
851pub enum Either2<A, B> {
852 First(A),
854 Second(B),
856}
857#[allow(dead_code)]
858impl<A, B> Either2<A, B> {
859 pub fn is_first(&self) -> bool {
861 matches!(self, Either2::First(_))
862 }
863 pub fn is_second(&self) -> bool {
865 matches!(self, Either2::Second(_))
866 }
867 pub fn first(self) -> Option<A> {
869 match self {
870 Either2::First(a) => Some(a),
871 _ => None,
872 }
873 }
874 pub fn second(self) -> Option<B> {
876 match self {
877 Either2::Second(b) => Some(b),
878 _ => None,
879 }
880 }
881 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
883 match self {
884 Either2::First(a) => Either2::First(f(a)),
885 Either2::Second(b) => Either2::Second(b),
886 }
887 }
888}
889#[allow(dead_code)]
891pub struct SlidingSum {
892 window: Vec<f64>,
893 capacity: usize,
894 pos: usize,
895 sum: f64,
896 count: usize,
897}
898#[allow(dead_code)]
899impl SlidingSum {
900 pub fn new(capacity: usize) -> Self {
902 Self {
903 window: vec![0.0; capacity],
904 capacity,
905 pos: 0,
906 sum: 0.0,
907 count: 0,
908 }
909 }
910 pub fn push(&mut self, val: f64) {
912 let oldest = self.window[self.pos];
913 self.sum -= oldest;
914 self.sum += val;
915 self.window[self.pos] = val;
916 self.pos = (self.pos + 1) % self.capacity;
917 if self.count < self.capacity {
918 self.count += 1;
919 }
920 }
921 pub fn sum(&self) -> f64 {
923 self.sum
924 }
925 pub fn mean(&self) -> Option<f64> {
927 if self.count == 0 {
928 None
929 } else {
930 Some(self.sum / self.count as f64)
931 }
932 }
933 pub fn count(&self) -> usize {
935 self.count
936 }
937}
938#[allow(dead_code)]
940#[allow(missing_docs)]
941pub struct RewriteRule {
942 pub name: String,
944 pub lhs: String,
946 pub rhs: String,
948 pub conditional: bool,
950}
951#[allow(dead_code)]
952impl RewriteRule {
953 pub fn unconditional(
955 name: impl Into<String>,
956 lhs: impl Into<String>,
957 rhs: impl Into<String>,
958 ) -> Self {
959 Self {
960 name: name.into(),
961 lhs: lhs.into(),
962 rhs: rhs.into(),
963 conditional: false,
964 }
965 }
966 pub fn conditional(
968 name: impl Into<String>,
969 lhs: impl Into<String>,
970 rhs: impl Into<String>,
971 ) -> Self {
972 Self {
973 name: name.into(),
974 lhs: lhs.into(),
975 rhs: rhs.into(),
976 conditional: true,
977 }
978 }
979 pub fn display(&self) -> String {
981 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
982 }
983}
984#[allow(dead_code)]
986pub struct StringPool {
987 free: Vec<String>,
988}
989#[allow(dead_code)]
990impl StringPool {
991 pub fn new() -> Self {
993 Self { free: Vec::new() }
994 }
995 pub fn take(&mut self) -> String {
997 self.free.pop().unwrap_or_default()
998 }
999 pub fn give(&mut self, mut s: String) {
1001 s.clear();
1002 self.free.push(s);
1003 }
1004 pub fn free_count(&self) -> usize {
1006 self.free.len()
1007 }
1008}
1009#[derive(Clone, Debug, PartialEq)]
1011pub enum WhnfHead {
1012 Sort(Level),
1014 BVar(u32),
1016 FVar(FVarId),
1018 Const(Name, Vec<Level>),
1020 Lam(BinderInfo, Name, Node, Node),
1022 Pi(BinderInfo, Name, Node, Node),
1024 Lit(Literal),
1026}
1027impl WhnfHead {
1028 pub fn to_expr(self) -> Expr {
1030 match self {
1031 WhnfHead::Sort(l) => Expr::Sort(l),
1032 WhnfHead::BVar(i) => Expr::BVar(i),
1033 WhnfHead::FVar(id) => Expr::FVar(id),
1034 WhnfHead::Const(n, ls) => Expr::Const(n, ls),
1035 WhnfHead::Lam(bi, n, ty, body) => Expr::Lam(bi, n, ty, body),
1036 WhnfHead::Pi(bi, n, ty, body) => Expr::Pi(bi, n, ty, body),
1037 WhnfHead::Lit(l) => Expr::Lit(l),
1038 }
1039 }
1040 pub fn as_const_name(&self) -> Option<&Name> {
1042 match self {
1043 WhnfHead::Const(n, _) => Some(n),
1044 _ => None,
1045 }
1046 }
1047}
1048#[allow(dead_code)]
1050pub struct TokenBucket {
1051 capacity: u64,
1052 tokens: u64,
1053 refill_per_ms: u64,
1054 last_refill: crate::wall_clock::Instant,
1055}
1056#[allow(dead_code)]
1057impl TokenBucket {
1058 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
1060 Self {
1061 capacity,
1062 tokens: capacity,
1063 refill_per_ms,
1064 last_refill: crate::wall_clock::Instant::now(),
1065 }
1066 }
1067 pub fn try_consume(&mut self, n: u64) -> bool {
1069 self.refill();
1070 if self.tokens >= n {
1071 self.tokens -= n;
1072 true
1073 } else {
1074 false
1075 }
1076 }
1077 fn refill(&mut self) {
1078 let now = crate::wall_clock::Instant::now();
1079 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
1080 if elapsed_ms > 0 {
1081 let new_tokens = elapsed_ms * self.refill_per_ms;
1082 self.tokens = (self.tokens + new_tokens).min(self.capacity);
1083 self.last_refill = now;
1084 }
1085 }
1086 pub fn available(&self) -> u64 {
1088 self.tokens
1089 }
1090 pub fn capacity(&self) -> u64 {
1092 self.capacity
1093 }
1094}
1095#[allow(dead_code)]
1097pub struct RawFnPtr {
1098 ptr: usize,
1100 arity: usize,
1101 name: String,
1102}
1103#[allow(dead_code)]
1104impl RawFnPtr {
1105 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
1107 Self {
1108 ptr,
1109 arity,
1110 name: name.into(),
1111 }
1112 }
1113 pub fn arity(&self) -> usize {
1115 self.arity
1116 }
1117 pub fn name(&self) -> &str {
1119 &self.name
1120 }
1121 pub fn raw(&self) -> usize {
1123 self.ptr
1124 }
1125}
1126#[derive(Debug, Default)]
1131pub struct WhnfCache {
1132 entries: Vec<(WhnfCacheKey, Expr)>,
1134 capacity: usize,
1136 hits: u64,
1138 misses: u64,
1140}
1141impl WhnfCache {
1142 pub fn new(capacity: usize) -> Self {
1144 Self {
1145 entries: Vec::with_capacity(capacity),
1146 capacity,
1147 hits: 0,
1148 misses: 0,
1149 }
1150 }
1151 pub fn get(&mut self, key: &WhnfCacheKey) -> Option<&Expr> {
1153 if let Some(pos) = self.entries.iter().position(|(k, _)| k == key) {
1154 self.hits += 1;
1155 Some(&self.entries[pos].1)
1156 } else {
1157 self.misses += 1;
1158 None
1159 }
1160 }
1161 pub fn insert(&mut self, key: WhnfCacheKey, value: Expr) {
1163 if self.entries.iter().any(|(k, _)| k == &key) {
1164 return;
1165 }
1166 if self.entries.len() >= self.capacity && self.capacity > 0 {
1167 self.entries.remove(0);
1168 }
1169 self.entries.push((key, value));
1170 }
1171 pub fn len(&self) -> usize {
1173 self.entries.len()
1174 }
1175 pub fn is_empty(&self) -> bool {
1177 self.entries.is_empty()
1178 }
1179 pub fn clear(&mut self) {
1181 self.entries.clear();
1182 }
1183 pub fn hits(&self) -> u64 {
1185 self.hits
1186 }
1187 pub fn misses(&self) -> u64 {
1189 self.misses
1190 }
1191 pub fn hit_rate(&self) -> f64 {
1193 let total = self.hits + self.misses;
1194 if total == 0 {
1195 0.0
1196 } else {
1197 self.hits as f64 / total as f64
1198 }
1199 }
1200}
1201#[allow(dead_code)]
1203pub struct Fixture {
1204 data: std::collections::HashMap<String, String>,
1205}
1206#[allow(dead_code)]
1207impl Fixture {
1208 pub fn new() -> Self {
1210 Self {
1211 data: std::collections::HashMap::new(),
1212 }
1213 }
1214 pub fn set(&mut self, key: impl Into<String>, val: impl Into<String>) {
1216 self.data.insert(key.into(), val.into());
1217 }
1218 pub fn get(&self, key: &str) -> Option<&str> {
1220 self.data.get(key).map(|s| s.as_str())
1221 }
1222 pub fn len(&self) -> usize {
1224 self.data.len()
1225 }
1226 pub fn is_empty(&self) -> bool {
1228 self.len() == 0
1229 }
1230}
1231#[derive(Clone, Debug)]
1233pub struct WhnfConfig {
1234 pub beta: bool,
1236 pub zeta: bool,
1238 pub delta: bool,
1240 pub iota: bool,
1242 pub max_steps: u64,
1244}
1245impl WhnfConfig {
1246 pub fn structural() -> Self {
1248 Self {
1249 beta: true,
1250 zeta: true,
1251 delta: false,
1252 iota: true,
1253 max_steps: 0,
1254 }
1255 }
1256 pub fn with_limit(max_steps: u64) -> Self {
1258 Self {
1259 max_steps,
1260 ..Self::default()
1261 }
1262 }
1263 pub fn no_delta(mut self) -> Self {
1265 self.delta = false;
1266 self
1267 }
1268 pub fn no_beta(mut self) -> Self {
1270 self.beta = false;
1271 self
1272 }
1273 pub fn any_enabled(&self) -> bool {
1275 self.beta || self.zeta || self.delta || self.iota
1276 }
1277}
1278#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1280pub struct WhnfCacheKey {
1281 pub expr_hash: u64,
1283}
1284impl WhnfCacheKey {
1285 pub fn from_expr(expr: &Expr) -> Self {
1287 use std::collections::hash_map::DefaultHasher;
1288 use std::hash::{Hash, Hasher};
1289 let mut hasher = DefaultHasher::new();
1290 format!("{:?}", expr).hash(&mut hasher);
1291 Self {
1292 expr_hash: hasher.finish(),
1293 }
1294 }
1295}
1296#[allow(dead_code)]
1298pub struct LabelSet {
1299 labels: Vec<String>,
1300}
1301#[allow(dead_code)]
1302impl LabelSet {
1303 pub fn new() -> Self {
1305 Self { labels: Vec::new() }
1306 }
1307 pub fn add(&mut self, label: impl Into<String>) {
1309 let s = label.into();
1310 if !self.labels.contains(&s) {
1311 self.labels.push(s);
1312 }
1313 }
1314 pub fn has(&self, label: &str) -> bool {
1316 self.labels.iter().any(|l| l == label)
1317 }
1318 pub fn count(&self) -> usize {
1320 self.labels.len()
1321 }
1322 pub fn all(&self) -> &[String] {
1324 &self.labels
1325 }
1326}
1327#[allow(dead_code)]
1329#[allow(missing_docs)]
1330pub enum DecisionNode {
1331 Leaf(String),
1333 Branch {
1335 key: String,
1336 val: String,
1337 yes_branch: Box<DecisionNode>,
1338 no_branch: Box<DecisionNode>,
1339 },
1340}
1341#[allow(dead_code)]
1342impl DecisionNode {
1343 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
1345 match self {
1346 DecisionNode::Leaf(action) => action.as_str(),
1347 DecisionNode::Branch {
1348 key,
1349 val,
1350 yes_branch,
1351 no_branch,
1352 } => {
1353 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
1354 if actual == val.as_str() {
1355 yes_branch.evaluate(ctx)
1356 } else {
1357 no_branch.evaluate(ctx)
1358 }
1359 }
1360 }
1361 }
1362 pub fn depth(&self) -> usize {
1364 match self {
1365 DecisionNode::Leaf(_) => 0,
1366 DecisionNode::Branch {
1367 yes_branch,
1368 no_branch,
1369 ..
1370 } => 1 + yes_branch.depth().max(no_branch.depth()),
1371 }
1372 }
1373}
1374#[allow(dead_code)]
1376pub struct WriteOnce<T> {
1377 value: std::cell::Cell<Option<T>>,
1378}
1379#[allow(dead_code)]
1380impl<T: Copy> WriteOnce<T> {
1381 pub fn new() -> Self {
1383 Self {
1384 value: std::cell::Cell::new(None),
1385 }
1386 }
1387 pub fn write(&self, val: T) -> bool {
1389 if self.value.get().is_some() {
1390 return false;
1391 }
1392 self.value.set(Some(val));
1393 true
1394 }
1395 pub fn read(&self) -> Option<T> {
1397 self.value.get()
1398 }
1399 pub fn is_written(&self) -> bool {
1401 self.value.get().is_some()
1402 }
1403}
1404#[allow(dead_code)]
1406pub struct SparseVec<T: Default + Clone + PartialEq> {
1407 entries: std::collections::HashMap<usize, T>,
1408 default_: T,
1409 logical_len: usize,
1410}
1411#[allow(dead_code)]
1412impl<T: Default + Clone + PartialEq> SparseVec<T> {
1413 pub fn new(len: usize) -> Self {
1415 Self {
1416 entries: std::collections::HashMap::new(),
1417 default_: T::default(),
1418 logical_len: len,
1419 }
1420 }
1421 pub fn set(&mut self, idx: usize, val: T) {
1423 if val == self.default_ {
1424 self.entries.remove(&idx);
1425 } else {
1426 self.entries.insert(idx, val);
1427 }
1428 }
1429 pub fn get(&self, idx: usize) -> &T {
1431 self.entries.get(&idx).unwrap_or(&self.default_)
1432 }
1433 pub fn len(&self) -> usize {
1435 self.logical_len
1436 }
1437 pub fn is_empty(&self) -> bool {
1439 self.len() == 0
1440 }
1441 pub fn nnz(&self) -> usize {
1443 self.entries.len()
1444 }
1445}
1446#[allow(dead_code)]
1448pub struct NonEmptyVec<T> {
1449 head: T,
1450 tail: Vec<T>,
1451}
1452#[allow(dead_code)]
1453impl<T> NonEmptyVec<T> {
1454 pub fn singleton(val: T) -> Self {
1456 Self {
1457 head: val,
1458 tail: Vec::new(),
1459 }
1460 }
1461 pub fn push(&mut self, val: T) {
1463 self.tail.push(val);
1464 }
1465 pub fn first(&self) -> &T {
1467 &self.head
1468 }
1469 pub fn last(&self) -> &T {
1471 self.tail.last().unwrap_or(&self.head)
1472 }
1473 pub fn len(&self) -> usize {
1475 1 + self.tail.len()
1476 }
1477 pub fn is_empty(&self) -> bool {
1479 self.len() == 0
1480 }
1481 pub fn to_vec(&self) -> Vec<&T> {
1483 let mut v = vec![&self.head];
1484 v.extend(self.tail.iter());
1485 v
1486 }
1487}