1use super::functions::*;
6use crate::{BinderInfo, Expr, FVarId, Name};
7use std::collections::HashMap;
8
9#[derive(Debug, Clone)]
11pub struct ContextSnapshot {
12 num_locals: usize,
14 next_fvar: u64,
16}
17#[allow(dead_code)]
19pub struct SparseVec<T: Default + Clone + PartialEq> {
20 entries: std::collections::HashMap<usize, T>,
21 default_: T,
22 logical_len: usize,
23}
24#[allow(dead_code)]
25impl<T: Default + Clone + PartialEq> SparseVec<T> {
26 pub fn new(len: usize) -> Self {
28 Self {
29 entries: std::collections::HashMap::new(),
30 default_: T::default(),
31 logical_len: len,
32 }
33 }
34 pub fn set(&mut self, idx: usize, val: T) {
36 if val == self.default_ {
37 self.entries.remove(&idx);
38 } else {
39 self.entries.insert(idx, val);
40 }
41 }
42 pub fn get(&self, idx: usize) -> &T {
44 self.entries.get(&idx).unwrap_or(&self.default_)
45 }
46 pub fn len(&self) -> usize {
48 self.logical_len
49 }
50 pub fn is_empty(&self) -> bool {
52 self.len() == 0
53 }
54 pub fn nnz(&self) -> usize {
56 self.entries.len()
57 }
58}
59#[allow(dead_code)]
61pub struct TransformStat {
62 before: StatSummary,
63 after: StatSummary,
64}
65#[allow(dead_code)]
66impl TransformStat {
67 pub fn new() -> Self {
69 Self {
70 before: StatSummary::new(),
71 after: StatSummary::new(),
72 }
73 }
74 pub fn record_before(&mut self, v: f64) {
76 self.before.record(v);
77 }
78 pub fn record_after(&mut self, v: f64) {
80 self.after.record(v);
81 }
82 pub fn mean_ratio(&self) -> Option<f64> {
84 let b = self.before.mean()?;
85 let a = self.after.mean()?;
86 if b.abs() < f64::EPSILON {
87 return None;
88 }
89 Some(a / b)
90 }
91}
92#[allow(dead_code)]
94pub struct TransitiveClosure {
95 adj: Vec<Vec<usize>>,
96 n: usize,
97}
98#[allow(dead_code)]
99impl TransitiveClosure {
100 pub fn new(n: usize) -> Self {
102 Self {
103 adj: vec![Vec::new(); n],
104 n,
105 }
106 }
107 pub fn add_edge(&mut self, from: usize, to: usize) {
109 if from < self.n {
110 self.adj[from].push(to);
111 }
112 }
113 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
115 let mut visited = vec![false; self.n];
116 let mut queue = std::collections::VecDeque::new();
117 queue.push_back(start);
118 while let Some(node) = queue.pop_front() {
119 if node >= self.n || visited[node] {
120 continue;
121 }
122 visited[node] = true;
123 for &next in &self.adj[node] {
124 queue.push_back(next);
125 }
126 }
127 (0..self.n).filter(|&i| visited[i]).collect()
128 }
129 pub fn can_reach(&self, from: usize, to: usize) -> bool {
131 self.reachable_from(from).contains(&to)
132 }
133}
134#[derive(Debug, Clone)]
136pub struct LocalVar {
137 pub name: Name,
139 pub binder_info: BinderInfo,
141 pub ty: Expr,
143 pub val: Option<Expr>,
145 pub fvar: FVarId,
147 pub index: usize,
149}
150#[allow(dead_code)]
152pub enum Either2<A, B> {
153 First(A),
155 Second(B),
157}
158#[allow(dead_code)]
159impl<A, B> Either2<A, B> {
160 pub fn is_first(&self) -> bool {
162 matches!(self, Either2::First(_))
163 }
164 pub fn is_second(&self) -> bool {
166 matches!(self, Either2::Second(_))
167 }
168 pub fn first(self) -> Option<A> {
170 match self {
171 Either2::First(a) => Some(a),
172 _ => None,
173 }
174 }
175 pub fn second(self) -> Option<B> {
177 match self {
178 Either2::Second(b) => Some(b),
179 _ => None,
180 }
181 }
182 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
184 match self {
185 Either2::First(a) => Either2::First(f(a)),
186 Either2::Second(b) => Either2::Second(b),
187 }
188 }
189}
190#[allow(dead_code)]
192pub struct StringPool {
193 free: Vec<String>,
194}
195#[allow(dead_code)]
196impl StringPool {
197 pub fn new() -> Self {
199 Self { free: Vec::new() }
200 }
201 pub fn take(&mut self) -> String {
203 self.free.pop().unwrap_or_default()
204 }
205 pub fn give(&mut self, mut s: String) {
207 s.clear();
208 self.free.push(s);
209 }
210 pub fn free_count(&self) -> usize {
212 self.free.len()
213 }
214}
215#[allow(dead_code)]
217pub struct SimpleDag {
218 edges: Vec<Vec<usize>>,
220}
221#[allow(dead_code)]
222impl SimpleDag {
223 pub fn new(n: usize) -> Self {
225 Self {
226 edges: vec![Vec::new(); n],
227 }
228 }
229 pub fn add_edge(&mut self, from: usize, to: usize) {
231 if from < self.edges.len() {
232 self.edges[from].push(to);
233 }
234 }
235 pub fn successors(&self, node: usize) -> &[usize] {
237 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
238 }
239 pub fn can_reach(&self, from: usize, to: usize) -> bool {
241 let mut visited = vec![false; self.edges.len()];
242 self.dfs(from, to, &mut visited)
243 }
244 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
245 if cur == target {
246 return true;
247 }
248 if cur >= visited.len() || visited[cur] {
249 return false;
250 }
251 visited[cur] = true;
252 for &next in self.successors(cur) {
253 if self.dfs(next, target, visited) {
254 return true;
255 }
256 }
257 false
258 }
259 pub fn topological_sort(&self) -> Option<Vec<usize>> {
261 let n = self.edges.len();
262 let mut in_degree = vec![0usize; n];
263 for succs in &self.edges {
264 for &s in succs {
265 if s < n {
266 in_degree[s] += 1;
267 }
268 }
269 }
270 let mut queue: std::collections::VecDeque<usize> =
271 (0..n).filter(|&i| in_degree[i] == 0).collect();
272 let mut order = Vec::new();
273 while let Some(node) = queue.pop_front() {
274 order.push(node);
275 for &s in self.successors(node) {
276 if s < n {
277 in_degree[s] -= 1;
278 if in_degree[s] == 0 {
279 queue.push_back(s);
280 }
281 }
282 }
283 }
284 if order.len() == n {
285 Some(order)
286 } else {
287 None
288 }
289 }
290 pub fn num_nodes(&self) -> usize {
292 self.edges.len()
293 }
294}
295#[allow(dead_code)]
297pub struct RewriteRuleSet {
298 rules: Vec<RewriteRule>,
299}
300#[allow(dead_code)]
301impl RewriteRuleSet {
302 pub fn new() -> Self {
304 Self { rules: Vec::new() }
305 }
306 pub fn add(&mut self, rule: RewriteRule) {
308 self.rules.push(rule);
309 }
310 pub fn len(&self) -> usize {
312 self.rules.len()
313 }
314 pub fn is_empty(&self) -> bool {
316 self.rules.is_empty()
317 }
318 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
320 self.rules.iter().filter(|r| r.conditional).collect()
321 }
322 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
324 self.rules.iter().filter(|r| !r.conditional).collect()
325 }
326 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
328 self.rules.iter().find(|r| r.name == name)
329 }
330}
331#[allow(dead_code)]
336#[derive(Debug, Clone)]
337pub struct ScopedContext {
338 inner: Context,
340 scope_stack: Vec<ContextSnapshot>,
342}
343impl ScopedContext {
344 #[allow(dead_code)]
346 pub fn new() -> Self {
347 Self {
348 inner: Context::new(),
349 scope_stack: Vec::new(),
350 }
351 }
352 #[allow(dead_code)]
354 pub fn push_scope(&mut self) {
355 self.scope_stack.push(self.inner.save());
356 }
357 #[allow(dead_code)]
359 pub fn pop_scope(&mut self) {
360 if let Some(snap) = self.scope_stack.pop() {
361 self.inner.restore(&snap);
362 }
363 }
364 #[allow(dead_code)]
366 pub fn add_local(&mut self, name: Name, ty: Expr) -> FVarId {
367 self.inner.push_local(name, ty, None)
368 }
369 #[allow(dead_code)]
371 pub fn get_local(&self, fvar: FVarId) -> Option<&LocalVar> {
372 self.inner.get_local(fvar)
373 }
374 #[allow(dead_code)]
376 pub fn scope_depth(&self) -> usize {
377 self.scope_stack.len()
378 }
379 #[allow(dead_code)]
381 pub fn num_locals(&self) -> usize {
382 self.inner.num_locals()
383 }
384 #[allow(dead_code)]
386 pub fn inner(&self) -> &Context {
387 &self.inner
388 }
389 #[allow(dead_code)]
391 pub fn get_fvars(&self) -> Vec<Expr> {
392 self.inner.get_fvars()
393 }
394}
395#[allow(dead_code)]
397#[derive(Debug, Clone)]
398pub struct FreshNameSeq {
399 base: String,
400 counter: u64,
401 used: Vec<String>,
402}
403impl FreshNameSeq {
404 #[allow(dead_code)]
406 pub fn new(base: &str) -> Self {
407 Self {
408 base: base.to_string(),
409 counter: 0,
410 used: Vec::new(),
411 }
412 }
413 #[allow(dead_code)]
415 #[allow(clippy::should_implement_trait)]
416 pub fn next(&mut self) -> Name {
417 loop {
418 let candidate = if self.counter == 0 {
419 self.base.clone()
420 } else {
421 format!("{}_{}", self.base, self.counter)
422 };
423 self.counter += 1;
424 if !self.used.contains(&candidate) {
425 self.used.push(candidate.clone());
426 return Name::str(&candidate);
427 }
428 }
429 }
430 #[allow(dead_code)]
432 pub fn reserve(&mut self, name: &str) {
433 if !self.used.contains(&name.to_string()) {
434 self.used.push(name.to_string());
435 }
436 }
437 #[allow(dead_code)]
439 pub fn count(&self) -> usize {
440 self.used.len()
441 }
442}
443#[allow(dead_code)]
445pub struct Stopwatch {
446 start: std::time::Instant,
447 splits: Vec<f64>,
448}
449#[allow(dead_code)]
450impl Stopwatch {
451 pub fn start() -> Self {
453 Self {
454 start: std::time::Instant::now(),
455 splits: Vec::new(),
456 }
457 }
458 pub fn split(&mut self) {
460 self.splits.push(self.elapsed_ms());
461 }
462 pub fn elapsed_ms(&self) -> f64 {
464 self.start.elapsed().as_secs_f64() * 1000.0
465 }
466 pub fn splits(&self) -> &[f64] {
468 &self.splits
469 }
470 pub fn num_splits(&self) -> usize {
472 self.splits.len()
473 }
474}
475#[allow(dead_code)]
477#[allow(missing_docs)]
478pub struct RewriteRule {
479 pub name: String,
481 pub lhs: String,
483 pub rhs: String,
485 pub conditional: bool,
487}
488#[allow(dead_code)]
489impl RewriteRule {
490 pub fn unconditional(
492 name: impl Into<String>,
493 lhs: impl Into<String>,
494 rhs: impl Into<String>,
495 ) -> Self {
496 Self {
497 name: name.into(),
498 lhs: lhs.into(),
499 rhs: rhs.into(),
500 conditional: false,
501 }
502 }
503 pub fn conditional(
505 name: impl Into<String>,
506 lhs: impl Into<String>,
507 rhs: impl Into<String>,
508 ) -> Self {
509 Self {
510 name: name.into(),
511 lhs: lhs.into(),
512 rhs: rhs.into(),
513 conditional: true,
514 }
515 }
516 pub fn display(&self) -> String {
518 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
519 }
520}
521#[allow(dead_code)]
523#[derive(Debug, Clone)]
524pub struct HypContext {
525 inner: Context,
526 hyps: Vec<(Name, FVarId)>,
528}
529impl HypContext {
530 #[allow(dead_code)]
532 pub fn new() -> Self {
533 Self {
534 inner: Context::new(),
535 hyps: Vec::new(),
536 }
537 }
538 #[allow(dead_code)]
540 pub fn add_hyp(&mut self, name: Name, ty: Expr) -> FVarId {
541 let fvar = self.inner.push_local(name.clone(), ty, None);
542 self.hyps.push((name, fvar));
543 fvar
544 }
545 #[allow(dead_code)]
547 pub fn find_hyp(&self, name: &Name) -> Option<FVarId> {
548 self.hyps
549 .iter()
550 .rev()
551 .find(|(n, _)| n == name)
552 .map(|(_, id)| *id)
553 }
554 #[allow(dead_code)]
556 pub fn hyp_type(&self, fvar: FVarId) -> Option<&Expr> {
557 self.inner.get_type(fvar)
558 }
559 #[allow(dead_code)]
561 pub fn num_hyps(&self) -> usize {
562 self.hyps.len()
563 }
564 #[allow(dead_code)]
566 pub fn hyp_names(&self) -> Vec<&Name> {
567 self.hyps.iter().map(|(n, _)| n).collect()
568 }
569 #[allow(dead_code)]
571 pub fn remove_last_hyp(&mut self) {
572 if let Some((_, _)) = self.hyps.pop() {
573 self.inner.pop_local();
574 }
575 }
576 #[allow(dead_code)]
578 pub fn clear(&mut self) {
579 self.hyps.clear();
580 self.inner.clear();
581 }
582}
583#[allow(dead_code)]
585pub struct FocusStack<T> {
586 items: Vec<T>,
587}
588#[allow(dead_code)]
589impl<T> FocusStack<T> {
590 pub fn new() -> Self {
592 Self { items: Vec::new() }
593 }
594 pub fn focus(&mut self, item: T) {
596 self.items.push(item);
597 }
598 pub fn blur(&mut self) -> Option<T> {
600 self.items.pop()
601 }
602 pub fn current(&self) -> Option<&T> {
604 self.items.last()
605 }
606 pub fn depth(&self) -> usize {
608 self.items.len()
609 }
610 pub fn is_empty(&self) -> bool {
612 self.items.is_empty()
613 }
614}
615#[allow(dead_code)]
617#[allow(missing_docs)]
618pub enum DecisionNode {
619 Leaf(String),
621 Branch {
623 key: String,
624 val: String,
625 yes_branch: Box<DecisionNode>,
626 no_branch: Box<DecisionNode>,
627 },
628}
629#[allow(dead_code)]
630impl DecisionNode {
631 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
633 match self {
634 DecisionNode::Leaf(action) => action.as_str(),
635 DecisionNode::Branch {
636 key,
637 val,
638 yes_branch,
639 no_branch,
640 } => {
641 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
642 if actual == val.as_str() {
643 yes_branch.evaluate(ctx)
644 } else {
645 no_branch.evaluate(ctx)
646 }
647 }
648 }
649 }
650 pub fn depth(&self) -> usize {
652 match self {
653 DecisionNode::Leaf(_) => 0,
654 DecisionNode::Branch {
655 yes_branch,
656 no_branch,
657 ..
658 } => 1 + yes_branch.depth().max(no_branch.depth()),
659 }
660 }
661}
662#[allow(dead_code)]
664pub struct StatSummary {
665 count: u64,
666 sum: f64,
667 min: f64,
668 max: f64,
669}
670#[allow(dead_code)]
671impl StatSummary {
672 pub fn new() -> Self {
674 Self {
675 count: 0,
676 sum: 0.0,
677 min: f64::INFINITY,
678 max: f64::NEG_INFINITY,
679 }
680 }
681 pub fn record(&mut self, val: f64) {
683 self.count += 1;
684 self.sum += val;
685 if val < self.min {
686 self.min = val;
687 }
688 if val > self.max {
689 self.max = val;
690 }
691 }
692 pub fn mean(&self) -> Option<f64> {
694 if self.count == 0 {
695 None
696 } else {
697 Some(self.sum / self.count as f64)
698 }
699 }
700 pub fn min(&self) -> Option<f64> {
702 if self.count == 0 {
703 None
704 } else {
705 Some(self.min)
706 }
707 }
708 pub fn max(&self) -> Option<f64> {
710 if self.count == 0 {
711 None
712 } else {
713 Some(self.max)
714 }
715 }
716 pub fn count(&self) -> u64 {
718 self.count
719 }
720}
721#[allow(dead_code)]
723pub struct ConfigNode {
724 key: String,
725 value: Option<String>,
726 children: Vec<ConfigNode>,
727}
728#[allow(dead_code)]
729impl ConfigNode {
730 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
732 Self {
733 key: key.into(),
734 value: Some(value.into()),
735 children: Vec::new(),
736 }
737 }
738 pub fn section(key: impl Into<String>) -> Self {
740 Self {
741 key: key.into(),
742 value: None,
743 children: Vec::new(),
744 }
745 }
746 pub fn add_child(&mut self, child: ConfigNode) {
748 self.children.push(child);
749 }
750 pub fn key(&self) -> &str {
752 &self.key
753 }
754 pub fn value(&self) -> Option<&str> {
756 self.value.as_deref()
757 }
758 pub fn num_children(&self) -> usize {
760 self.children.len()
761 }
762 pub fn lookup(&self, path: &str) -> Option<&str> {
764 let mut parts = path.splitn(2, '.');
765 let head = parts.next()?;
766 let tail = parts.next();
767 if head != self.key {
768 return None;
769 }
770 match tail {
771 None => self.value.as_deref(),
772 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
773 }
774 }
775 fn lookup_relative(&self, path: &str) -> Option<&str> {
776 let mut parts = path.splitn(2, '.');
777 let head = parts.next()?;
778 let tail = parts.next();
779 if head != self.key {
780 return None;
781 }
782 match tail {
783 None => self.value.as_deref(),
784 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
785 }
786 }
787}
788#[allow(dead_code)]
790pub struct NonEmptyVec<T> {
791 head: T,
792 tail: Vec<T>,
793}
794#[allow(dead_code)]
795impl<T> NonEmptyVec<T> {
796 pub fn singleton(val: T) -> Self {
798 Self {
799 head: val,
800 tail: Vec::new(),
801 }
802 }
803 pub fn push(&mut self, val: T) {
805 self.tail.push(val);
806 }
807 pub fn first(&self) -> &T {
809 &self.head
810 }
811 pub fn last(&self) -> &T {
813 self.tail.last().unwrap_or(&self.head)
814 }
815 pub fn len(&self) -> usize {
817 1 + self.tail.len()
818 }
819 pub fn is_empty(&self) -> bool {
821 self.len() == 0
822 }
823 pub fn to_vec(&self) -> Vec<&T> {
825 let mut v = vec![&self.head];
826 v.extend(self.tail.iter());
827 v
828 }
829}
830#[derive(Debug, Clone)]
832pub struct Context {
833 locals: Vec<LocalVar>,
835 fvar_map: HashMap<FVarId, usize>,
837 next_fvar: u64,
839}
840impl Context {
841 pub fn new() -> Self {
843 Self {
844 locals: Vec::new(),
845 fvar_map: HashMap::new(),
846 next_fvar: 0,
847 }
848 }
849 pub fn with_start_fvar(start: u64) -> Self {
851 Self {
852 locals: Vec::new(),
853 fvar_map: HashMap::new(),
854 next_fvar: start,
855 }
856 }
857 pub fn fresh_fvar(&mut self) -> FVarId {
859 let fvar = FVarId(self.next_fvar);
860 self.next_fvar += 1;
861 fvar
862 }
863 pub fn push_local(&mut self, name: Name, ty: Expr, val: Option<Expr>) -> FVarId {
865 self.push_local_with_binder(name, BinderInfo::Default, ty, val)
866 }
867 pub fn push_local_with_binder(
869 &mut self,
870 name: Name,
871 binder_info: BinderInfo,
872 ty: Expr,
873 val: Option<Expr>,
874 ) -> FVarId {
875 let fvar = self.fresh_fvar();
876 let index = self.locals.len();
877 self.locals.push(LocalVar {
878 name,
879 binder_info,
880 ty,
881 val,
882 fvar,
883 index,
884 });
885 self.fvar_map.insert(fvar, index);
886 fvar
887 }
888 pub fn mk_local_decl(&mut self, name: Name, binder_info: BinderInfo, ty: Expr) -> Expr {
890 let fvar = self.push_local_with_binder(name, binder_info, ty, None);
891 Expr::FVar(fvar)
892 }
893 pub fn mk_let_decl(&mut self, name: Name, ty: Expr, val: Expr) -> Expr {
895 let fvar = self.push_local(name, ty, Some(val));
896 Expr::FVar(fvar)
897 }
898 pub fn pop_local(&mut self) -> Option<LocalVar> {
900 if let Some(local) = self.locals.pop() {
901 self.fvar_map.remove(&local.fvar);
902 Some(local)
903 } else {
904 None
905 }
906 }
907 pub fn save(&self) -> ContextSnapshot {
909 ContextSnapshot {
910 num_locals: self.locals.len(),
911 next_fvar: self.next_fvar,
912 }
913 }
914 pub fn restore(&mut self, snapshot: &ContextSnapshot) {
916 while self.locals.len() > snapshot.num_locals {
917 self.pop_local();
918 }
919 self.next_fvar = snapshot.next_fvar;
920 }
921 pub fn get_local(&self, fvar: FVarId) -> Option<&LocalVar> {
923 self.fvar_map
924 .get(&fvar)
925 .and_then(|&idx| self.locals.get(idx))
926 }
927 pub fn get_type(&self, fvar: FVarId) -> Option<&Expr> {
929 self.get_local(fvar).map(|l| &l.ty)
930 }
931 pub fn get_value(&self, fvar: FVarId) -> Option<&Expr> {
933 self.get_local(fvar).and_then(|l| l.val.as_ref())
934 }
935 pub fn is_let(&self, fvar: FVarId) -> bool {
937 self.get_local(fvar).is_some_and(|l| l.val.is_some())
938 }
939 pub fn find_local(&self, name: &Name) -> Option<&LocalVar> {
941 self.locals.iter().rev().find(|local| &local.name == name)
942 }
943 pub fn num_locals(&self) -> usize {
945 self.locals.len()
946 }
947 pub fn is_empty(&self) -> bool {
949 self.locals.is_empty()
950 }
951 pub fn all_locals(&self) -> &[LocalVar] {
953 &self.locals
954 }
955 pub fn get_fvars(&self) -> Vec<Expr> {
957 self.locals.iter().map(|l| Expr::FVar(l.fvar)).collect()
958 }
959 pub fn mk_lambda(&self, fvars: &[FVarId], body: Expr) -> Expr {
965 let mut result = body;
966 for &fvar in fvars.iter().rev() {
967 if let Some(local) = self.get_local(fvar) {
968 result = abstract_fvar(result, fvar);
969 result = Expr::Lam(
970 local.binder_info,
971 local.name.clone(),
972 Box::new(abstract_fvars_in_type(local.ty.clone(), fvars, fvar)),
973 Box::new(result),
974 );
975 }
976 }
977 result
978 }
979 pub fn mk_pi(&self, fvars: &[FVarId], body: Expr) -> Expr {
984 let mut result = body;
985 for &fvar in fvars.iter().rev() {
986 if let Some(local) = self.get_local(fvar) {
987 result = abstract_fvar(result, fvar);
988 result = Expr::Pi(
989 local.binder_info,
990 local.name.clone(),
991 Box::new(abstract_fvars_in_type(local.ty.clone(), fvars, fvar)),
992 Box::new(result),
993 );
994 }
995 }
996 result
997 }
998 pub fn clear(&mut self) {
1000 self.locals.clear();
1001 self.fvar_map.clear();
1002 }
1003 pub fn with_local<F, R>(&mut self, name: Name, ty: Expr, f: F) -> R
1007 where
1008 F: FnOnce(&mut Self, FVarId) -> R,
1009 {
1010 let fvar = self.push_local(name, ty, None);
1011 let result = f(self, fvar);
1012 self.pop_local();
1013 result
1014 }
1015}
1016#[allow(dead_code)]
1018pub struct WriteOnce<T> {
1019 value: std::cell::Cell<Option<T>>,
1020}
1021#[allow(dead_code)]
1022impl<T: Copy> WriteOnce<T> {
1023 pub fn new() -> Self {
1025 Self {
1026 value: std::cell::Cell::new(None),
1027 }
1028 }
1029 pub fn write(&self, val: T) -> bool {
1031 if self.value.get().is_some() {
1032 return false;
1033 }
1034 self.value.set(Some(val));
1035 true
1036 }
1037 pub fn read(&self) -> Option<T> {
1039 self.value.get()
1040 }
1041 pub fn is_written(&self) -> bool {
1043 self.value.get().is_some()
1044 }
1045}
1046#[allow(dead_code)]
1048pub struct SmallMap<K: Ord + Clone, V: Clone> {
1049 entries: Vec<(K, V)>,
1050}
1051#[allow(dead_code)]
1052impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
1053 pub fn new() -> Self {
1055 Self {
1056 entries: Vec::new(),
1057 }
1058 }
1059 pub fn insert(&mut self, key: K, val: V) {
1061 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
1062 Ok(i) => self.entries[i].1 = val,
1063 Err(i) => self.entries.insert(i, (key, val)),
1064 }
1065 }
1066 pub fn get(&self, key: &K) -> Option<&V> {
1068 self.entries
1069 .binary_search_by_key(&key, |(k, _)| k)
1070 .ok()
1071 .map(|i| &self.entries[i].1)
1072 }
1073 pub fn len(&self) -> usize {
1075 self.entries.len()
1076 }
1077 pub fn is_empty(&self) -> bool {
1079 self.entries.is_empty()
1080 }
1081 pub fn keys(&self) -> Vec<&K> {
1083 self.entries.iter().map(|(k, _)| k).collect()
1084 }
1085 pub fn values(&self) -> Vec<&V> {
1087 self.entries.iter().map(|(_, v)| v).collect()
1088 }
1089}
1090#[allow(dead_code)]
1092#[derive(Debug, Clone)]
1093pub struct ContextEntry {
1094 pub name: Name,
1096 pub ty: Expr,
1098 pub val: Option<Expr>,
1100 pub binder_info: BinderInfo,
1102}
1103impl ContextEntry {
1104 #[allow(dead_code)]
1106 pub fn local(name: Name, ty: Expr) -> Self {
1107 Self {
1108 name,
1109 ty,
1110 val: None,
1111 binder_info: BinderInfo::Default,
1112 }
1113 }
1114 #[allow(dead_code)]
1116 pub fn implicit(name: Name, ty: Expr) -> Self {
1117 Self {
1118 name,
1119 ty,
1120 val: None,
1121 binder_info: BinderInfo::Implicit,
1122 }
1123 }
1124 #[allow(dead_code)]
1126 pub fn let_binding(name: Name, ty: Expr, val: Expr) -> Self {
1127 Self {
1128 name,
1129 ty,
1130 val: Some(val),
1131 binder_info: BinderInfo::Default,
1132 }
1133 }
1134 #[allow(dead_code)]
1136 pub fn is_let(&self) -> bool {
1137 self.val.is_some()
1138 }
1139 #[allow(dead_code)]
1141 pub fn is_implicit(&self) -> bool {
1142 matches!(self.binder_info, BinderInfo::Implicit)
1143 }
1144}
1145#[allow(dead_code)]
1147pub struct WindowIterator<'a, T> {
1148 pub(super) data: &'a [T],
1149 pub(super) pos: usize,
1150 pub(super) window: usize,
1151}
1152#[allow(dead_code)]
1153impl<'a, T> WindowIterator<'a, T> {
1154 pub fn new(data: &'a [T], window: usize) -> Self {
1156 Self {
1157 data,
1158 pos: 0,
1159 window,
1160 }
1161 }
1162}
1163#[allow(dead_code)]
1165pub struct SlidingSum {
1166 window: Vec<f64>,
1167 capacity: usize,
1168 pos: usize,
1169 sum: f64,
1170 count: usize,
1171}
1172#[allow(dead_code)]
1173impl SlidingSum {
1174 pub fn new(capacity: usize) -> Self {
1176 Self {
1177 window: vec![0.0; capacity],
1178 capacity,
1179 pos: 0,
1180 sum: 0.0,
1181 count: 0,
1182 }
1183 }
1184 pub fn push(&mut self, val: f64) {
1186 let oldest = self.window[self.pos];
1187 self.sum -= oldest;
1188 self.sum += val;
1189 self.window[self.pos] = val;
1190 self.pos = (self.pos + 1) % self.capacity;
1191 if self.count < self.capacity {
1192 self.count += 1;
1193 }
1194 }
1195 pub fn sum(&self) -> f64 {
1197 self.sum
1198 }
1199 pub fn mean(&self) -> Option<f64> {
1201 if self.count == 0 {
1202 None
1203 } else {
1204 Some(self.sum / self.count as f64)
1205 }
1206 }
1207 pub fn count(&self) -> usize {
1209 self.count
1210 }
1211}
1212#[allow(dead_code)]
1214#[derive(Debug, Clone, Default)]
1215pub struct ContextChain {
1216 entries: Vec<ContextEntry>,
1217}
1218impl ContextChain {
1219 #[allow(dead_code)]
1221 pub fn new() -> Self {
1222 Self::default()
1223 }
1224 #[allow(dead_code)]
1226 pub fn push(&mut self, entry: ContextEntry) {
1227 self.entries.push(entry);
1228 }
1229 #[allow(dead_code)]
1231 pub fn pop(&mut self) -> Option<ContextEntry> {
1232 self.entries.pop()
1233 }
1234 #[allow(dead_code)]
1236 pub fn len(&self) -> usize {
1237 self.entries.len()
1238 }
1239 #[allow(dead_code)]
1241 pub fn is_empty(&self) -> bool {
1242 self.entries.is_empty()
1243 }
1244 #[allow(dead_code)]
1246 pub fn entries(&self) -> &[ContextEntry] {
1247 &self.entries
1248 }
1249 #[allow(dead_code)]
1251 pub fn num_lets(&self) -> usize {
1252 self.entries.iter().filter(|e| e.is_let()).count()
1253 }
1254 #[allow(dead_code)]
1256 pub fn num_implicit(&self) -> usize {
1257 self.entries.iter().filter(|e| e.is_implicit()).count()
1258 }
1259 #[allow(dead_code)]
1261 pub fn find(&self, name: &Name) -> Option<&ContextEntry> {
1262 self.entries.iter().rev().find(|e| &e.name == name)
1263 }
1264 #[allow(dead_code)]
1266 pub fn from_context(ctx: &Context) -> Self {
1267 let mut chain = Self::new();
1268 for local in ctx.all_locals() {
1269 chain.push(ContextEntry {
1270 name: local.name.clone(),
1271 ty: local.ty.clone(),
1272 val: local.val.clone(),
1273 binder_info: local.binder_info,
1274 });
1275 }
1276 chain
1277 }
1278}
1279#[allow(dead_code)]
1281pub struct LabelSet {
1282 labels: Vec<String>,
1283}
1284#[allow(dead_code)]
1285impl LabelSet {
1286 pub fn new() -> Self {
1288 Self { labels: Vec::new() }
1289 }
1290 pub fn add(&mut self, label: impl Into<String>) {
1292 let s = label.into();
1293 if !self.labels.contains(&s) {
1294 self.labels.push(s);
1295 }
1296 }
1297 pub fn has(&self, label: &str) -> bool {
1299 self.labels.iter().any(|l| l == label)
1300 }
1301 pub fn count(&self) -> usize {
1303 self.labels.len()
1304 }
1305 pub fn all(&self) -> &[String] {
1307 &self.labels
1308 }
1309}
1310#[allow(dead_code)]
1312#[derive(Debug, Clone, Default)]
1313pub struct ContextDiff {
1314 pub added: Vec<Name>,
1316 pub removed: Vec<Name>,
1318}
1319impl ContextDiff {
1320 #[allow(dead_code)]
1322 pub fn compute(old: &Context, new: &Context) -> Self {
1323 let old_names: std::collections::HashSet<&Name> =
1324 old.all_locals().iter().map(|l| &l.name).collect();
1325 let new_names: std::collections::HashSet<&Name> =
1326 new.all_locals().iter().map(|l| &l.name).collect();
1327 let added = new_names
1328 .difference(&old_names)
1329 .map(|&n| n.clone())
1330 .collect();
1331 let removed = old_names
1332 .difference(&new_names)
1333 .map(|&n| n.clone())
1334 .collect();
1335 Self { added, removed }
1336 }
1337 #[allow(dead_code)]
1339 pub fn is_empty(&self) -> bool {
1340 self.added.is_empty() && self.removed.is_empty()
1341 }
1342}
1343#[allow(dead_code)]
1345pub struct PathBuf {
1346 components: Vec<String>,
1347}
1348#[allow(dead_code)]
1349impl PathBuf {
1350 pub fn new() -> Self {
1352 Self {
1353 components: Vec::new(),
1354 }
1355 }
1356 pub fn push(&mut self, comp: impl Into<String>) {
1358 self.components.push(comp.into());
1359 }
1360 pub fn pop(&mut self) {
1362 self.components.pop();
1363 }
1364 pub fn as_str(&self) -> String {
1366 self.components.join("/")
1367 }
1368 pub fn depth(&self) -> usize {
1370 self.components.len()
1371 }
1372 pub fn clear(&mut self) {
1374 self.components.clear();
1375 }
1376}
1377#[derive(Debug, Clone)]
1379pub struct NameGenerator {
1380 prefix: String,
1382 next: u64,
1384}
1385impl NameGenerator {
1386 pub fn new(prefix: impl Into<String>) -> Self {
1388 Self {
1389 prefix: prefix.into(),
1390 next: 0,
1391 }
1392 }
1393 #[allow(clippy::should_implement_trait)]
1395 pub fn next(&mut self) -> Name {
1396 let n = self.next;
1397 self.next += 1;
1398 Name::str(format!("{}_{}", self.prefix, n))
1399 }
1400 pub fn next_fvar_id(&mut self) -> FVarId {
1402 let n = self.next;
1403 self.next += 1;
1404 FVarId(n)
1405 }
1406}
1407#[allow(dead_code)]
1409pub struct StackCalc {
1410 stack: Vec<i64>,
1411}
1412#[allow(dead_code)]
1413impl StackCalc {
1414 pub fn new() -> Self {
1416 Self { stack: Vec::new() }
1417 }
1418 pub fn push(&mut self, n: i64) {
1420 self.stack.push(n);
1421 }
1422 pub fn add(&mut self) {
1424 let b = self
1425 .stack
1426 .pop()
1427 .expect("stack must have at least two values for add");
1428 let a = self
1429 .stack
1430 .pop()
1431 .expect("stack must have at least two values for add");
1432 self.stack.push(a + b);
1433 }
1434 pub fn sub(&mut self) {
1436 let b = self
1437 .stack
1438 .pop()
1439 .expect("stack must have at least two values for sub");
1440 let a = self
1441 .stack
1442 .pop()
1443 .expect("stack must have at least two values for sub");
1444 self.stack.push(a - b);
1445 }
1446 pub fn mul(&mut self) {
1448 let b = self
1449 .stack
1450 .pop()
1451 .expect("stack must have at least two values for mul");
1452 let a = self
1453 .stack
1454 .pop()
1455 .expect("stack must have at least two values for mul");
1456 self.stack.push(a * b);
1457 }
1458 pub fn peek(&self) -> Option<i64> {
1460 self.stack.last().copied()
1461 }
1462 pub fn depth(&self) -> usize {
1464 self.stack.len()
1465 }
1466}
1467#[allow(dead_code)]
1469#[derive(Debug, Clone, Default)]
1470pub struct ContextStats {
1471 pub num_locals: usize,
1473 pub num_lets: usize,
1475 pub num_implicit: usize,
1477 pub max_depth: usize,
1479}
1480impl ContextStats {
1481 #[allow(dead_code)]
1483 pub fn from_context(ctx: &Context) -> Self {
1484 let locals = ctx.all_locals();
1485 let num_lets = locals.iter().filter(|l| l.val.is_some()).count();
1486 let num_implicit = locals
1487 .iter()
1488 .filter(|l| matches!(l.binder_info, BinderInfo::Implicit))
1489 .count();
1490 Self {
1491 num_locals: locals.len(),
1492 num_lets,
1493 num_implicit,
1494 max_depth: locals.len(),
1495 }
1496 }
1497}
1498#[allow(dead_code)]
1500pub struct RawFnPtr {
1501 ptr: usize,
1503 arity: usize,
1504 name: String,
1505}
1506#[allow(dead_code)]
1507impl RawFnPtr {
1508 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
1510 Self {
1511 ptr,
1512 arity,
1513 name: name.into(),
1514 }
1515 }
1516 pub fn arity(&self) -> usize {
1518 self.arity
1519 }
1520 pub fn name(&self) -> &str {
1522 &self.name
1523 }
1524 pub fn raw(&self) -> usize {
1526 self.ptr
1527 }
1528}
1529#[allow(dead_code)]
1531pub struct TokenBucket {
1532 capacity: u64,
1533 tokens: u64,
1534 refill_per_ms: u64,
1535 last_refill: std::time::Instant,
1536}
1537#[allow(dead_code)]
1538impl TokenBucket {
1539 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
1541 Self {
1542 capacity,
1543 tokens: capacity,
1544 refill_per_ms,
1545 last_refill: std::time::Instant::now(),
1546 }
1547 }
1548 pub fn try_consume(&mut self, n: u64) -> bool {
1550 self.refill();
1551 if self.tokens >= n {
1552 self.tokens -= n;
1553 true
1554 } else {
1555 false
1556 }
1557 }
1558 fn refill(&mut self) {
1559 let now = std::time::Instant::now();
1560 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
1561 if elapsed_ms > 0 {
1562 let new_tokens = elapsed_ms * self.refill_per_ms;
1563 self.tokens = (self.tokens + new_tokens).min(self.capacity);
1564 self.last_refill = now;
1565 }
1566 }
1567 pub fn available(&self) -> u64 {
1569 self.tokens
1570 }
1571 pub fn capacity(&self) -> u64 {
1573 self.capacity
1574 }
1575}
1576#[allow(dead_code)]
1578pub struct FlatSubstitution {
1579 pairs: Vec<(String, String)>,
1580}
1581#[allow(dead_code)]
1582impl FlatSubstitution {
1583 pub fn new() -> Self {
1585 Self { pairs: Vec::new() }
1586 }
1587 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
1589 self.pairs.push((from.into(), to.into()));
1590 }
1591 pub fn apply(&self, s: &str) -> String {
1593 let mut result = s.to_string();
1594 for (from, to) in &self.pairs {
1595 result = result.replace(from.as_str(), to.as_str());
1596 }
1597 result
1598 }
1599 pub fn len(&self) -> usize {
1601 self.pairs.len()
1602 }
1603 pub fn is_empty(&self) -> bool {
1605 self.pairs.is_empty()
1606 }
1607}
1608#[allow(dead_code)]
1610pub struct VersionedRecord<T: Clone> {
1611 history: Vec<T>,
1612}
1613#[allow(dead_code)]
1614impl<T: Clone> VersionedRecord<T> {
1615 pub fn new(initial: T) -> Self {
1617 Self {
1618 history: vec![initial],
1619 }
1620 }
1621 pub fn update(&mut self, val: T) {
1623 self.history.push(val);
1624 }
1625 pub fn current(&self) -> &T {
1627 self.history
1628 .last()
1629 .expect("VersionedRecord history is always non-empty after construction")
1630 }
1631 pub fn at_version(&self, n: usize) -> Option<&T> {
1633 self.history.get(n)
1634 }
1635 pub fn version(&self) -> usize {
1637 self.history.len() - 1
1638 }
1639 pub fn has_history(&self) -> bool {
1641 self.history.len() > 1
1642 }
1643}