1use crate::{BinderInfo, Environment, Expr, FVarId, Level, Literal, Name, Reducer};
6
7use std::collections::HashMap;
8
9#[allow(dead_code)]
11pub struct ConfigNode {
12 key: String,
13 value: Option<String>,
14 children: Vec<ConfigNode>,
15}
16#[allow(dead_code)]
17impl ConfigNode {
18 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
20 Self {
21 key: key.into(),
22 value: Some(value.into()),
23 children: Vec::new(),
24 }
25 }
26 pub fn section(key: impl Into<String>) -> Self {
28 Self {
29 key: key.into(),
30 value: None,
31 children: Vec::new(),
32 }
33 }
34 pub fn add_child(&mut self, child: ConfigNode) {
36 self.children.push(child);
37 }
38 pub fn key(&self) -> &str {
40 &self.key
41 }
42 pub fn value(&self) -> Option<&str> {
44 self.value.as_deref()
45 }
46 pub fn num_children(&self) -> usize {
48 self.children.len()
49 }
50 pub fn lookup(&self, path: &str) -> Option<&str> {
52 let mut parts = path.splitn(2, '.');
53 let head = parts.next()?;
54 let tail = parts.next();
55 if head != self.key {
56 return None;
57 }
58 match tail {
59 None => self.value.as_deref(),
60 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
61 }
62 }
63 fn lookup_relative(&self, path: &str) -> Option<&str> {
64 let mut parts = path.splitn(2, '.');
65 let head = parts.next()?;
66 let tail = parts.next();
67 if head != self.key {
68 return None;
69 }
70 match tail {
71 None => self.value.as_deref(),
72 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
73 }
74 }
75}
76#[allow(dead_code)]
78pub struct PrefixCounter {
79 children: std::collections::HashMap<char, PrefixCounter>,
80 count: usize,
81}
82#[allow(dead_code)]
83impl PrefixCounter {
84 pub fn new() -> Self {
86 Self {
87 children: std::collections::HashMap::new(),
88 count: 0,
89 }
90 }
91 pub fn record(&mut self, s: &str) {
93 self.count += 1;
94 let mut node = self;
95 for c in s.chars() {
96 node = node.children.entry(c).or_default();
97 node.count += 1;
98 }
99 }
100 pub fn count_with_prefix(&self, prefix: &str) -> usize {
102 let mut node = self;
103 for c in prefix.chars() {
104 match node.children.get(&c) {
105 Some(n) => node = n,
106 None => return 0,
107 }
108 }
109 node.count
110 }
111}
112#[allow(dead_code)]
114pub struct FlatSubstitution {
115 pairs: Vec<(String, String)>,
116}
117#[allow(dead_code)]
118impl FlatSubstitution {
119 pub fn new() -> Self {
121 Self { pairs: Vec::new() }
122 }
123 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
125 self.pairs.push((from.into(), to.into()));
126 }
127 pub fn apply(&self, s: &str) -> String {
129 let mut result = s.to_string();
130 for (from, to) in &self.pairs {
131 result = result.replace(from.as_str(), to.as_str());
132 }
133 result
134 }
135 pub fn len(&self) -> usize {
137 self.pairs.len()
138 }
139 pub fn is_empty(&self) -> bool {
141 self.pairs.is_empty()
142 }
143}
144#[allow(dead_code)]
146pub struct VersionedRecord<T: Clone> {
147 history: Vec<T>,
148}
149#[allow(dead_code)]
150impl<T: Clone> VersionedRecord<T> {
151 pub fn new(initial: T) -> Self {
153 Self {
154 history: vec![initial],
155 }
156 }
157 pub fn update(&mut self, val: T) {
159 self.history.push(val);
160 }
161 pub fn current(&self) -> &T {
163 self.history
164 .last()
165 .expect("VersionedRecord history is always non-empty after construction")
166 }
167 pub fn at_version(&self, n: usize) -> Option<&T> {
169 self.history.get(n)
170 }
171 pub fn version(&self) -> usize {
173 self.history.len() - 1
174 }
175 pub fn has_history(&self) -> bool {
177 self.history.len() > 1
178 }
179}
180#[allow(dead_code)]
182pub struct WindowIterator<'a, T> {
183 pub(super) data: &'a [T],
184 pub(super) pos: usize,
185 pub(super) window: usize,
186}
187#[allow(dead_code)]
188impl<'a, T> WindowIterator<'a, T> {
189 pub fn new(data: &'a [T], window: usize) -> Self {
191 Self {
192 data,
193 pos: 0,
194 window,
195 }
196 }
197}
198#[allow(dead_code)]
200pub struct MinHeap<T: Ord> {
201 data: Vec<T>,
202}
203#[allow(dead_code)]
204impl<T: Ord> MinHeap<T> {
205 pub fn new() -> Self {
207 Self { data: Vec::new() }
208 }
209 pub fn push(&mut self, val: T) {
211 self.data.push(val);
212 self.sift_up(self.data.len() - 1);
213 }
214 pub fn pop(&mut self) -> Option<T> {
216 if self.data.is_empty() {
217 return None;
218 }
219 let n = self.data.len();
220 self.data.swap(0, n - 1);
221 let min = self.data.pop();
222 if !self.data.is_empty() {
223 self.sift_down(0);
224 }
225 min
226 }
227 pub fn peek(&self) -> Option<&T> {
229 self.data.first()
230 }
231 pub fn len(&self) -> usize {
233 self.data.len()
234 }
235 pub fn is_empty(&self) -> bool {
237 self.data.is_empty()
238 }
239 fn sift_up(&mut self, mut i: usize) {
240 while i > 0 {
241 let parent = (i - 1) / 2;
242 if self.data[i] < self.data[parent] {
243 self.data.swap(i, parent);
244 i = parent;
245 } else {
246 break;
247 }
248 }
249 }
250 fn sift_down(&mut self, mut i: usize) {
251 let n = self.data.len();
252 loop {
253 let left = 2 * i + 1;
254 let right = 2 * i + 2;
255 let mut smallest = i;
256 if left < n && self.data[left] < self.data[smallest] {
257 smallest = left;
258 }
259 if right < n && self.data[right] < self.data[smallest] {
260 smallest = right;
261 }
262 if smallest == i {
263 break;
264 }
265 self.data.swap(i, smallest);
266 i = smallest;
267 }
268 }
269}
270#[derive(Clone, Debug, Default)]
272pub struct WhnfStats {
273 pub beta_steps: u64,
275 pub delta_steps: u64,
277 pub zeta_steps: u64,
279 pub iota_steps: u64,
281 pub total_exprs: u64,
283}
284impl WhnfStats {
285 pub fn new() -> Self {
287 Self::default()
288 }
289 pub fn total_steps(&self) -> u64 {
291 self.beta_steps + self.delta_steps + self.zeta_steps + self.iota_steps
292 }
293 pub fn any_progress(&self) -> bool {
295 self.total_steps() > 0
296 }
297}
298#[allow(dead_code)]
300pub struct StackCalc {
301 stack: Vec<i64>,
302}
303#[allow(dead_code)]
304impl StackCalc {
305 pub fn new() -> Self {
307 Self { stack: Vec::new() }
308 }
309 pub fn push(&mut self, n: i64) {
311 self.stack.push(n);
312 }
313 pub fn add(&mut self) {
315 let b = self
316 .stack
317 .pop()
318 .expect("stack must have at least two values for add");
319 let a = self
320 .stack
321 .pop()
322 .expect("stack must have at least two values for add");
323 self.stack.push(a + b);
324 }
325 pub fn sub(&mut self) {
327 let b = self
328 .stack
329 .pop()
330 .expect("stack must have at least two values for sub");
331 let a = self
332 .stack
333 .pop()
334 .expect("stack must have at least two values for sub");
335 self.stack.push(a - b);
336 }
337 pub fn mul(&mut self) {
339 let b = self
340 .stack
341 .pop()
342 .expect("stack must have at least two values for mul");
343 let a = self
344 .stack
345 .pop()
346 .expect("stack must have at least two values for mul");
347 self.stack.push(a * b);
348 }
349 pub fn peek(&self) -> Option<i64> {
351 self.stack.last().copied()
352 }
353 pub fn depth(&self) -> usize {
355 self.stack.len()
356 }
357}
358#[allow(dead_code)]
360pub struct FocusStack<T> {
361 items: Vec<T>,
362}
363#[allow(dead_code)]
364impl<T> FocusStack<T> {
365 pub fn new() -> Self {
367 Self { items: Vec::new() }
368 }
369 pub fn focus(&mut self, item: T) {
371 self.items.push(item);
372 }
373 pub fn blur(&mut self) -> Option<T> {
375 self.items.pop()
376 }
377 pub fn current(&self) -> Option<&T> {
379 self.items.last()
380 }
381 pub fn depth(&self) -> usize {
383 self.items.len()
384 }
385 pub fn is_empty(&self) -> bool {
387 self.items.is_empty()
388 }
389}
390#[derive(Clone, Copy, Debug, PartialEq, Eq)]
392pub struct ReductionBudget {
393 pub remaining: u64,
395}
396impl ReductionBudget {
397 pub fn new(n: u64) -> Self {
399 Self { remaining: n }
400 }
401 pub fn unlimited() -> Self {
403 Self {
404 remaining: u64::MAX,
405 }
406 }
407 pub fn consume(&mut self) -> bool {
409 if self.remaining == 0 {
410 return false;
411 }
412 self.remaining -= 1;
413 true
414 }
415 pub fn is_active(&self) -> bool {
417 self.remaining > 0
418 }
419}
420#[allow(dead_code)]
422pub struct TransformStat {
423 before: StatSummary,
424 after: StatSummary,
425}
426#[allow(dead_code)]
427impl TransformStat {
428 pub fn new() -> Self {
430 Self {
431 before: StatSummary::new(),
432 after: StatSummary::new(),
433 }
434 }
435 pub fn record_before(&mut self, v: f64) {
437 self.before.record(v);
438 }
439 pub fn record_after(&mut self, v: f64) {
441 self.after.record(v);
442 }
443 pub fn mean_ratio(&self) -> Option<f64> {
445 let b = self.before.mean()?;
446 let a = self.after.mean()?;
447 if b.abs() < f64::EPSILON {
448 return None;
449 }
450 Some(a / b)
451 }
452}
453#[allow(dead_code)]
455pub struct SimpleDag {
456 edges: Vec<Vec<usize>>,
458}
459#[allow(dead_code)]
460impl SimpleDag {
461 pub fn new(n: usize) -> Self {
463 Self {
464 edges: vec![Vec::new(); n],
465 }
466 }
467 pub fn add_edge(&mut self, from: usize, to: usize) {
469 if from < self.edges.len() {
470 self.edges[from].push(to);
471 }
472 }
473 pub fn successors(&self, node: usize) -> &[usize] {
475 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
476 }
477 pub fn can_reach(&self, from: usize, to: usize) -> bool {
479 let mut visited = vec![false; self.edges.len()];
480 self.dfs(from, to, &mut visited)
481 }
482 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
483 if cur == target {
484 return true;
485 }
486 if cur >= visited.len() || visited[cur] {
487 return false;
488 }
489 visited[cur] = true;
490 for &next in self.successors(cur) {
491 if self.dfs(next, target, visited) {
492 return true;
493 }
494 }
495 false
496 }
497 pub fn topological_sort(&self) -> Option<Vec<usize>> {
499 let n = self.edges.len();
500 let mut in_degree = vec![0usize; n];
501 for succs in &self.edges {
502 for &s in succs {
503 if s < n {
504 in_degree[s] += 1;
505 }
506 }
507 }
508 let mut queue: std::collections::VecDeque<usize> =
509 (0..n).filter(|&i| in_degree[i] == 0).collect();
510 let mut order = Vec::new();
511 while let Some(node) = queue.pop_front() {
512 order.push(node);
513 for &s in self.successors(node) {
514 if s < n {
515 in_degree[s] -= 1;
516 if in_degree[s] == 0 {
517 queue.push_back(s);
518 }
519 }
520 }
521 }
522 if order.len() == n {
523 Some(order)
524 } else {
525 None
526 }
527 }
528 pub fn num_nodes(&self) -> usize {
530 self.edges.len()
531 }
532}
533#[derive(Clone, Debug)]
535pub struct WhnfDepthBudget {
536 pub budget: u32,
538 pub remaining: u32,
540}
541impl WhnfDepthBudget {
542 pub fn new(budget: u32) -> Self {
544 Self {
545 budget,
546 remaining: budget,
547 }
548 }
549 pub fn unlimited() -> Self {
551 Self {
552 budget: u32::MAX,
553 remaining: u32::MAX,
554 }
555 }
556 pub fn consume(&mut self) -> bool {
558 if self.remaining > 0 {
559 self.remaining -= 1;
560 true
561 } else {
562 false
563 }
564 }
565 pub fn is_exhausted(&self) -> bool {
567 self.remaining == 0
568 }
569 pub fn consumed(&self) -> u32 {
571 self.budget.saturating_sub(self.remaining)
572 }
573 pub fn reset(&mut self) {
575 self.remaining = self.budget;
576 }
577}
578#[derive(Clone, Debug, PartialEq, Eq)]
580pub enum StuckReason {
581 FreeVariable(FVarId),
583 OpaqueConst(Name),
585 NormalForm,
587}
588#[allow(dead_code)]
590pub struct SmallMap<K: Ord + Clone, V: Clone> {
591 entries: Vec<(K, V)>,
592}
593#[allow(dead_code)]
594impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
595 pub fn new() -> Self {
597 Self {
598 entries: Vec::new(),
599 }
600 }
601 pub fn insert(&mut self, key: K, val: V) {
603 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
604 Ok(i) => self.entries[i].1 = val,
605 Err(i) => self.entries.insert(i, (key, val)),
606 }
607 }
608 pub fn get(&self, key: &K) -> Option<&V> {
610 self.entries
611 .binary_search_by_key(&key, |(k, _)| k)
612 .ok()
613 .map(|i| &self.entries[i].1)
614 }
615 pub fn len(&self) -> usize {
617 self.entries.len()
618 }
619 pub fn is_empty(&self) -> bool {
621 self.entries.is_empty()
622 }
623 pub fn keys(&self) -> Vec<&K> {
625 self.entries.iter().map(|(k, _)| k).collect()
626 }
627 pub fn values(&self) -> Vec<&V> {
629 self.entries.iter().map(|(_, v)| v).collect()
630 }
631}
632#[allow(dead_code)]
634pub struct StatSummary {
635 count: u64,
636 sum: f64,
637 min: f64,
638 max: f64,
639}
640#[allow(dead_code)]
641impl StatSummary {
642 pub fn new() -> Self {
644 Self {
645 count: 0,
646 sum: 0.0,
647 min: f64::INFINITY,
648 max: f64::NEG_INFINITY,
649 }
650 }
651 pub fn record(&mut self, val: f64) {
653 self.count += 1;
654 self.sum += val;
655 if val < self.min {
656 self.min = val;
657 }
658 if val > self.max {
659 self.max = val;
660 }
661 }
662 pub fn mean(&self) -> Option<f64> {
664 if self.count == 0 {
665 None
666 } else {
667 Some(self.sum / self.count as f64)
668 }
669 }
670 pub fn min(&self) -> Option<f64> {
672 if self.count == 0 {
673 None
674 } else {
675 Some(self.min)
676 }
677 }
678 pub fn max(&self) -> Option<f64> {
680 if self.count == 0 {
681 None
682 } else {
683 Some(self.max)
684 }
685 }
686 pub fn count(&self) -> u64 {
688 self.count
689 }
690}
691#[allow(dead_code)]
693pub struct PathBuf {
694 components: Vec<String>,
695}
696#[allow(dead_code)]
697impl PathBuf {
698 pub fn new() -> Self {
700 Self {
701 components: Vec::new(),
702 }
703 }
704 pub fn push(&mut self, comp: impl Into<String>) {
706 self.components.push(comp.into());
707 }
708 pub fn pop(&mut self) {
710 self.components.pop();
711 }
712 pub fn as_str(&self) -> String {
714 self.components.join("/")
715 }
716 pub fn depth(&self) -> usize {
718 self.components.len()
719 }
720 pub fn clear(&mut self) {
722 self.components.clear();
723 }
724}
725#[allow(dead_code)]
727pub struct TransitiveClosure {
728 adj: Vec<Vec<usize>>,
729 n: usize,
730}
731#[allow(dead_code)]
732impl TransitiveClosure {
733 pub fn new(n: usize) -> Self {
735 Self {
736 adj: vec![Vec::new(); n],
737 n,
738 }
739 }
740 pub fn add_edge(&mut self, from: usize, to: usize) {
742 if from < self.n {
743 self.adj[from].push(to);
744 }
745 }
746 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
748 let mut visited = vec![false; self.n];
749 let mut queue = std::collections::VecDeque::new();
750 queue.push_back(start);
751 while let Some(node) = queue.pop_front() {
752 if node >= self.n || visited[node] {
753 continue;
754 }
755 visited[node] = true;
756 for &next in &self.adj[node] {
757 queue.push_back(next);
758 }
759 }
760 (0..self.n).filter(|&i| visited[i]).collect()
761 }
762 pub fn can_reach(&self, from: usize, to: usize) -> bool {
764 self.reachable_from(from).contains(&to)
765 }
766}
767#[allow(dead_code)]
769pub struct RewriteRuleSet {
770 rules: Vec<RewriteRule>,
771}
772#[allow(dead_code)]
773impl RewriteRuleSet {
774 pub fn new() -> Self {
776 Self { rules: Vec::new() }
777 }
778 pub fn add(&mut self, rule: RewriteRule) {
780 self.rules.push(rule);
781 }
782 pub fn len(&self) -> usize {
784 self.rules.len()
785 }
786 pub fn is_empty(&self) -> bool {
788 self.rules.is_empty()
789 }
790 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
792 self.rules.iter().filter(|r| r.conditional).collect()
793 }
794 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
796 self.rules.iter().filter(|r| !r.conditional).collect()
797 }
798 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
800 self.rules.iter().find(|r| r.name == name)
801 }
802}
803#[derive(Clone, Copy, Debug, PartialEq, Eq)]
805pub enum WhnfReductionOrder {
806 BetaFirst,
808 DeltaFirst,
810 StructuralOnly,
812}
813#[allow(dead_code)]
815pub struct Stopwatch {
816 start: std::time::Instant,
817 splits: Vec<f64>,
818}
819#[allow(dead_code)]
820impl Stopwatch {
821 pub fn start() -> Self {
823 Self {
824 start: std::time::Instant::now(),
825 splits: Vec::new(),
826 }
827 }
828 pub fn split(&mut self) {
830 self.splits.push(self.elapsed_ms());
831 }
832 pub fn elapsed_ms(&self) -> f64 {
834 self.start.elapsed().as_secs_f64() * 1000.0
835 }
836 pub fn splits(&self) -> &[f64] {
838 &self.splits
839 }
840 pub fn num_splits(&self) -> usize {
842 self.splits.len()
843 }
844}
845#[allow(dead_code)]
847pub enum Either2<A, B> {
848 First(A),
850 Second(B),
852}
853#[allow(dead_code)]
854impl<A, B> Either2<A, B> {
855 pub fn is_first(&self) -> bool {
857 matches!(self, Either2::First(_))
858 }
859 pub fn is_second(&self) -> bool {
861 matches!(self, Either2::Second(_))
862 }
863 pub fn first(self) -> Option<A> {
865 match self {
866 Either2::First(a) => Some(a),
867 _ => None,
868 }
869 }
870 pub fn second(self) -> Option<B> {
872 match self {
873 Either2::Second(b) => Some(b),
874 _ => None,
875 }
876 }
877 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
879 match self {
880 Either2::First(a) => Either2::First(f(a)),
881 Either2::Second(b) => Either2::Second(b),
882 }
883 }
884}
885#[allow(dead_code)]
887pub struct SlidingSum {
888 window: Vec<f64>,
889 capacity: usize,
890 pos: usize,
891 sum: f64,
892 count: usize,
893}
894#[allow(dead_code)]
895impl SlidingSum {
896 pub fn new(capacity: usize) -> Self {
898 Self {
899 window: vec![0.0; capacity],
900 capacity,
901 pos: 0,
902 sum: 0.0,
903 count: 0,
904 }
905 }
906 pub fn push(&mut self, val: f64) {
908 let oldest = self.window[self.pos];
909 self.sum -= oldest;
910 self.sum += val;
911 self.window[self.pos] = val;
912 self.pos = (self.pos + 1) % self.capacity;
913 if self.count < self.capacity {
914 self.count += 1;
915 }
916 }
917 pub fn sum(&self) -> f64 {
919 self.sum
920 }
921 pub fn mean(&self) -> Option<f64> {
923 if self.count == 0 {
924 None
925 } else {
926 Some(self.sum / self.count as f64)
927 }
928 }
929 pub fn count(&self) -> usize {
931 self.count
932 }
933}
934#[allow(dead_code)]
936#[allow(missing_docs)]
937pub struct RewriteRule {
938 pub name: String,
940 pub lhs: String,
942 pub rhs: String,
944 pub conditional: bool,
946}
947#[allow(dead_code)]
948impl RewriteRule {
949 pub fn unconditional(
951 name: impl Into<String>,
952 lhs: impl Into<String>,
953 rhs: impl Into<String>,
954 ) -> Self {
955 Self {
956 name: name.into(),
957 lhs: lhs.into(),
958 rhs: rhs.into(),
959 conditional: false,
960 }
961 }
962 pub fn conditional(
964 name: impl Into<String>,
965 lhs: impl Into<String>,
966 rhs: impl Into<String>,
967 ) -> Self {
968 Self {
969 name: name.into(),
970 lhs: lhs.into(),
971 rhs: rhs.into(),
972 conditional: true,
973 }
974 }
975 pub fn display(&self) -> String {
977 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
978 }
979}
980#[allow(dead_code)]
982pub struct StringPool {
983 free: Vec<String>,
984}
985#[allow(dead_code)]
986impl StringPool {
987 pub fn new() -> Self {
989 Self { free: Vec::new() }
990 }
991 pub fn take(&mut self) -> String {
993 self.free.pop().unwrap_or_default()
994 }
995 pub fn give(&mut self, mut s: String) {
997 s.clear();
998 self.free.push(s);
999 }
1000 pub fn free_count(&self) -> usize {
1002 self.free.len()
1003 }
1004}
1005#[derive(Clone, Debug, PartialEq)]
1007pub enum WhnfHead {
1008 Sort(Level),
1010 BVar(u32),
1012 FVar(FVarId),
1014 Const(Name, Vec<Level>),
1016 Lam(BinderInfo, Name, Box<Expr>, Box<Expr>),
1018 Pi(BinderInfo, Name, Box<Expr>, Box<Expr>),
1020 Lit(Literal),
1022}
1023impl WhnfHead {
1024 pub fn to_expr(self) -> Expr {
1026 match self {
1027 WhnfHead::Sort(l) => Expr::Sort(l),
1028 WhnfHead::BVar(i) => Expr::BVar(i),
1029 WhnfHead::FVar(id) => Expr::FVar(id),
1030 WhnfHead::Const(n, ls) => Expr::Const(n, ls),
1031 WhnfHead::Lam(bi, n, ty, body) => Expr::Lam(bi, n, ty, body),
1032 WhnfHead::Pi(bi, n, ty, body) => Expr::Pi(bi, n, ty, body),
1033 WhnfHead::Lit(l) => Expr::Lit(l),
1034 }
1035 }
1036 pub fn as_const_name(&self) -> Option<&Name> {
1038 match self {
1039 WhnfHead::Const(n, _) => Some(n),
1040 _ => None,
1041 }
1042 }
1043}
1044#[allow(dead_code)]
1046pub struct TokenBucket {
1047 capacity: u64,
1048 tokens: u64,
1049 refill_per_ms: u64,
1050 last_refill: std::time::Instant,
1051}
1052#[allow(dead_code)]
1053impl TokenBucket {
1054 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
1056 Self {
1057 capacity,
1058 tokens: capacity,
1059 refill_per_ms,
1060 last_refill: std::time::Instant::now(),
1061 }
1062 }
1063 pub fn try_consume(&mut self, n: u64) -> bool {
1065 self.refill();
1066 if self.tokens >= n {
1067 self.tokens -= n;
1068 true
1069 } else {
1070 false
1071 }
1072 }
1073 fn refill(&mut self) {
1074 let now = std::time::Instant::now();
1075 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
1076 if elapsed_ms > 0 {
1077 let new_tokens = elapsed_ms * self.refill_per_ms;
1078 self.tokens = (self.tokens + new_tokens).min(self.capacity);
1079 self.last_refill = now;
1080 }
1081 }
1082 pub fn available(&self) -> u64 {
1084 self.tokens
1085 }
1086 pub fn capacity(&self) -> u64 {
1088 self.capacity
1089 }
1090}
1091#[allow(dead_code)]
1093pub struct RawFnPtr {
1094 ptr: usize,
1096 arity: usize,
1097 name: String,
1098}
1099#[allow(dead_code)]
1100impl RawFnPtr {
1101 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
1103 Self {
1104 ptr,
1105 arity,
1106 name: name.into(),
1107 }
1108 }
1109 pub fn arity(&self) -> usize {
1111 self.arity
1112 }
1113 pub fn name(&self) -> &str {
1115 &self.name
1116 }
1117 pub fn raw(&self) -> usize {
1119 self.ptr
1120 }
1121}
1122#[derive(Debug, Default)]
1127pub struct WhnfCache {
1128 entries: Vec<(WhnfCacheKey, Expr)>,
1130 capacity: usize,
1132 hits: u64,
1134 misses: u64,
1136}
1137impl WhnfCache {
1138 pub fn new(capacity: usize) -> Self {
1140 Self {
1141 entries: Vec::with_capacity(capacity),
1142 capacity,
1143 hits: 0,
1144 misses: 0,
1145 }
1146 }
1147 pub fn get(&mut self, key: &WhnfCacheKey) -> Option<&Expr> {
1149 if let Some(pos) = self.entries.iter().position(|(k, _)| k == key) {
1150 self.hits += 1;
1151 Some(&self.entries[pos].1)
1152 } else {
1153 self.misses += 1;
1154 None
1155 }
1156 }
1157 pub fn insert(&mut self, key: WhnfCacheKey, value: Expr) {
1159 if self.entries.iter().any(|(k, _)| k == &key) {
1160 return;
1161 }
1162 if self.entries.len() >= self.capacity && self.capacity > 0 {
1163 self.entries.remove(0);
1164 }
1165 self.entries.push((key, value));
1166 }
1167 pub fn len(&self) -> usize {
1169 self.entries.len()
1170 }
1171 pub fn is_empty(&self) -> bool {
1173 self.entries.is_empty()
1174 }
1175 pub fn clear(&mut self) {
1177 self.entries.clear();
1178 }
1179 pub fn hits(&self) -> u64 {
1181 self.hits
1182 }
1183 pub fn misses(&self) -> u64 {
1185 self.misses
1186 }
1187 pub fn hit_rate(&self) -> f64 {
1189 let total = self.hits + self.misses;
1190 if total == 0 {
1191 0.0
1192 } else {
1193 self.hits as f64 / total as f64
1194 }
1195 }
1196}
1197#[allow(dead_code)]
1199pub struct Fixture {
1200 data: std::collections::HashMap<String, String>,
1201}
1202#[allow(dead_code)]
1203impl Fixture {
1204 pub fn new() -> Self {
1206 Self {
1207 data: std::collections::HashMap::new(),
1208 }
1209 }
1210 pub fn set(&mut self, key: impl Into<String>, val: impl Into<String>) {
1212 self.data.insert(key.into(), val.into());
1213 }
1214 pub fn get(&self, key: &str) -> Option<&str> {
1216 self.data.get(key).map(|s| s.as_str())
1217 }
1218 pub fn len(&self) -> usize {
1220 self.data.len()
1221 }
1222 pub fn is_empty(&self) -> bool {
1224 self.len() == 0
1225 }
1226}
1227#[derive(Clone, Debug)]
1229pub struct WhnfConfig {
1230 pub beta: bool,
1232 pub zeta: bool,
1234 pub delta: bool,
1236 pub iota: bool,
1238 pub max_steps: u64,
1240}
1241impl WhnfConfig {
1242 pub fn structural() -> Self {
1244 Self {
1245 beta: true,
1246 zeta: true,
1247 delta: false,
1248 iota: true,
1249 max_steps: 0,
1250 }
1251 }
1252 pub fn with_limit(max_steps: u64) -> Self {
1254 Self {
1255 max_steps,
1256 ..Self::default()
1257 }
1258 }
1259 pub fn no_delta(mut self) -> Self {
1261 self.delta = false;
1262 self
1263 }
1264 pub fn no_beta(mut self) -> Self {
1266 self.beta = false;
1267 self
1268 }
1269 pub fn any_enabled(&self) -> bool {
1271 self.beta || self.zeta || self.delta || self.iota
1272 }
1273}
1274#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1276pub struct WhnfCacheKey {
1277 pub expr_hash: u64,
1279}
1280impl WhnfCacheKey {
1281 pub fn from_expr(expr: &Expr) -> Self {
1283 use std::collections::hash_map::DefaultHasher;
1284 use std::hash::{Hash, Hasher};
1285 let mut hasher = DefaultHasher::new();
1286 format!("{:?}", expr).hash(&mut hasher);
1287 Self {
1288 expr_hash: hasher.finish(),
1289 }
1290 }
1291}
1292#[allow(dead_code)]
1294pub struct LabelSet {
1295 labels: Vec<String>,
1296}
1297#[allow(dead_code)]
1298impl LabelSet {
1299 pub fn new() -> Self {
1301 Self { labels: Vec::new() }
1302 }
1303 pub fn add(&mut self, label: impl Into<String>) {
1305 let s = label.into();
1306 if !self.labels.contains(&s) {
1307 self.labels.push(s);
1308 }
1309 }
1310 pub fn has(&self, label: &str) -> bool {
1312 self.labels.iter().any(|l| l == label)
1313 }
1314 pub fn count(&self) -> usize {
1316 self.labels.len()
1317 }
1318 pub fn all(&self) -> &[String] {
1320 &self.labels
1321 }
1322}
1323#[allow(dead_code)]
1325#[allow(missing_docs)]
1326pub enum DecisionNode {
1327 Leaf(String),
1329 Branch {
1331 key: String,
1332 val: String,
1333 yes_branch: Box<DecisionNode>,
1334 no_branch: Box<DecisionNode>,
1335 },
1336}
1337#[allow(dead_code)]
1338impl DecisionNode {
1339 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
1341 match self {
1342 DecisionNode::Leaf(action) => action.as_str(),
1343 DecisionNode::Branch {
1344 key,
1345 val,
1346 yes_branch,
1347 no_branch,
1348 } => {
1349 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
1350 if actual == val.as_str() {
1351 yes_branch.evaluate(ctx)
1352 } else {
1353 no_branch.evaluate(ctx)
1354 }
1355 }
1356 }
1357 }
1358 pub fn depth(&self) -> usize {
1360 match self {
1361 DecisionNode::Leaf(_) => 0,
1362 DecisionNode::Branch {
1363 yes_branch,
1364 no_branch,
1365 ..
1366 } => 1 + yes_branch.depth().max(no_branch.depth()),
1367 }
1368 }
1369}
1370#[allow(dead_code)]
1372pub struct WriteOnce<T> {
1373 value: std::cell::Cell<Option<T>>,
1374}
1375#[allow(dead_code)]
1376impl<T: Copy> WriteOnce<T> {
1377 pub fn new() -> Self {
1379 Self {
1380 value: std::cell::Cell::new(None),
1381 }
1382 }
1383 pub fn write(&self, val: T) -> bool {
1385 if self.value.get().is_some() {
1386 return false;
1387 }
1388 self.value.set(Some(val));
1389 true
1390 }
1391 pub fn read(&self) -> Option<T> {
1393 self.value.get()
1394 }
1395 pub fn is_written(&self) -> bool {
1397 self.value.get().is_some()
1398 }
1399}
1400#[allow(dead_code)]
1402pub struct SparseVec<T: Default + Clone + PartialEq> {
1403 entries: std::collections::HashMap<usize, T>,
1404 default_: T,
1405 logical_len: usize,
1406}
1407#[allow(dead_code)]
1408impl<T: Default + Clone + PartialEq> SparseVec<T> {
1409 pub fn new(len: usize) -> Self {
1411 Self {
1412 entries: std::collections::HashMap::new(),
1413 default_: T::default(),
1414 logical_len: len,
1415 }
1416 }
1417 pub fn set(&mut self, idx: usize, val: T) {
1419 if val == self.default_ {
1420 self.entries.remove(&idx);
1421 } else {
1422 self.entries.insert(idx, val);
1423 }
1424 }
1425 pub fn get(&self, idx: usize) -> &T {
1427 self.entries.get(&idx).unwrap_or(&self.default_)
1428 }
1429 pub fn len(&self) -> usize {
1431 self.logical_len
1432 }
1433 pub fn is_empty(&self) -> bool {
1435 self.len() == 0
1436 }
1437 pub fn nnz(&self) -> usize {
1439 self.entries.len()
1440 }
1441}
1442#[allow(dead_code)]
1444pub struct NonEmptyVec<T> {
1445 head: T,
1446 tail: Vec<T>,
1447}
1448#[allow(dead_code)]
1449impl<T> NonEmptyVec<T> {
1450 pub fn singleton(val: T) -> Self {
1452 Self {
1453 head: val,
1454 tail: Vec::new(),
1455 }
1456 }
1457 pub fn push(&mut self, val: T) {
1459 self.tail.push(val);
1460 }
1461 pub fn first(&self) -> &T {
1463 &self.head
1464 }
1465 pub fn last(&self) -> &T {
1467 self.tail.last().unwrap_or(&self.head)
1468 }
1469 pub fn len(&self) -> usize {
1471 1 + self.tail.len()
1472 }
1473 pub fn is_empty(&self) -> bool {
1475 self.len() == 0
1476 }
1477 pub fn to_vec(&self) -> Vec<&T> {
1479 let mut v = vec![&self.head];
1480 v.extend(self.tail.iter());
1481 v
1482 }
1483}