1use super::functions::*;
6use crate::Node;
7use crate::{BinderInfo, Expr, FVarId, Name};
8use std::collections::HashMap;
9use std::rc::Rc;
10
11#[derive(Debug, Clone)]
13pub struct ContextSnapshot {
14 num_locals: usize,
16 next_fvar: u64,
18}
19#[allow(dead_code)]
21pub struct SparseVec<T: Default + Clone + PartialEq> {
22 entries: std::collections::HashMap<usize, T>,
23 default_: T,
24 logical_len: usize,
25}
26#[allow(dead_code)]
27impl<T: Default + Clone + PartialEq> SparseVec<T> {
28 pub fn new(len: usize) -> Self {
30 Self {
31 entries: std::collections::HashMap::new(),
32 default_: T::default(),
33 logical_len: len,
34 }
35 }
36 pub fn set(&mut self, idx: usize, val: T) {
38 if val == self.default_ {
39 self.entries.remove(&idx);
40 } else {
41 self.entries.insert(idx, val);
42 }
43 }
44 pub fn get(&self, idx: usize) -> &T {
46 self.entries.get(&idx).unwrap_or(&self.default_)
47 }
48 pub fn len(&self) -> usize {
50 self.logical_len
51 }
52 pub fn is_empty(&self) -> bool {
54 self.len() == 0
55 }
56 pub fn nnz(&self) -> usize {
58 self.entries.len()
59 }
60}
61#[allow(dead_code)]
63pub struct TransformStat {
64 before: StatSummary,
65 after: StatSummary,
66}
67#[allow(dead_code)]
68impl TransformStat {
69 pub fn new() -> Self {
71 Self {
72 before: StatSummary::new(),
73 after: StatSummary::new(),
74 }
75 }
76 pub fn record_before(&mut self, v: f64) {
78 self.before.record(v);
79 }
80 pub fn record_after(&mut self, v: f64) {
82 self.after.record(v);
83 }
84 pub fn mean_ratio(&self) -> Option<f64> {
86 let b = self.before.mean()?;
87 let a = self.after.mean()?;
88 if b.abs() < f64::EPSILON {
89 return None;
90 }
91 Some(a / b)
92 }
93}
94#[allow(dead_code)]
96pub struct TransitiveClosure {
97 adj: Vec<Vec<usize>>,
98 n: usize,
99}
100#[allow(dead_code)]
101impl TransitiveClosure {
102 pub fn new(n: usize) -> Self {
104 Self {
105 adj: vec![Vec::new(); n],
106 n,
107 }
108 }
109 pub fn add_edge(&mut self, from: usize, to: usize) {
111 if from < self.n {
112 self.adj[from].push(to);
113 }
114 }
115 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
117 let mut visited = vec![false; self.n];
118 let mut queue = std::collections::VecDeque::new();
119 queue.push_back(start);
120 while let Some(node) = queue.pop_front() {
121 if node >= self.n || visited[node] {
122 continue;
123 }
124 visited[node] = true;
125 for &next in &self.adj[node] {
126 queue.push_back(next);
127 }
128 }
129 (0..self.n).filter(|&i| visited[i]).collect()
130 }
131 pub fn can_reach(&self, from: usize, to: usize) -> bool {
133 self.reachable_from(from).contains(&to)
134 }
135}
136#[derive(Debug, Clone)]
138pub struct LocalVar {
139 pub name: Name,
141 pub binder_info: BinderInfo,
143 pub ty: Expr,
145 pub val: Option<Expr>,
147 pub fvar: FVarId,
149 pub index: usize,
151}
152#[allow(dead_code)]
154pub enum Either2<A, B> {
155 First(A),
157 Second(B),
159}
160#[allow(dead_code)]
161impl<A, B> Either2<A, B> {
162 pub fn is_first(&self) -> bool {
164 matches!(self, Either2::First(_))
165 }
166 pub fn is_second(&self) -> bool {
168 matches!(self, Either2::Second(_))
169 }
170 pub fn first(self) -> Option<A> {
172 match self {
173 Either2::First(a) => Some(a),
174 _ => None,
175 }
176 }
177 pub fn second(self) -> Option<B> {
179 match self {
180 Either2::Second(b) => Some(b),
181 _ => None,
182 }
183 }
184 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
186 match self {
187 Either2::First(a) => Either2::First(f(a)),
188 Either2::Second(b) => Either2::Second(b),
189 }
190 }
191}
192#[allow(dead_code)]
194pub struct StringPool {
195 free: Vec<String>,
196}
197#[allow(dead_code)]
198impl StringPool {
199 pub fn new() -> Self {
201 Self { free: Vec::new() }
202 }
203 pub fn take(&mut self) -> String {
205 self.free.pop().unwrap_or_default()
206 }
207 pub fn give(&mut self, mut s: String) {
209 s.clear();
210 self.free.push(s);
211 }
212 pub fn free_count(&self) -> usize {
214 self.free.len()
215 }
216}
217#[allow(dead_code)]
219pub struct SimpleDag {
220 edges: Vec<Vec<usize>>,
222}
223#[allow(dead_code)]
224impl SimpleDag {
225 pub fn new(n: usize) -> Self {
227 Self {
228 edges: vec![Vec::new(); n],
229 }
230 }
231 pub fn add_edge(&mut self, from: usize, to: usize) {
233 if from < self.edges.len() {
234 self.edges[from].push(to);
235 }
236 }
237 pub fn successors(&self, node: usize) -> &[usize] {
239 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
240 }
241 pub fn can_reach(&self, from: usize, to: usize) -> bool {
243 let mut visited = vec![false; self.edges.len()];
244 self.dfs(from, to, &mut visited)
245 }
246 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
247 if cur == target {
248 return true;
249 }
250 if cur >= visited.len() || visited[cur] {
251 return false;
252 }
253 visited[cur] = true;
254 for &next in self.successors(cur) {
255 if self.dfs(next, target, visited) {
256 return true;
257 }
258 }
259 false
260 }
261 pub fn topological_sort(&self) -> Option<Vec<usize>> {
263 let n = self.edges.len();
264 let mut in_degree = vec![0usize; n];
265 for succs in &self.edges {
266 for &s in succs {
267 if s < n {
268 in_degree[s] += 1;
269 }
270 }
271 }
272 let mut queue: std::collections::VecDeque<usize> =
273 (0..n).filter(|&i| in_degree[i] == 0).collect();
274 let mut order = Vec::new();
275 while let Some(node) = queue.pop_front() {
276 order.push(node);
277 for &s in self.successors(node) {
278 if s < n {
279 in_degree[s] -= 1;
280 if in_degree[s] == 0 {
281 queue.push_back(s);
282 }
283 }
284 }
285 }
286 if order.len() == n {
287 Some(order)
288 } else {
289 None
290 }
291 }
292 pub fn num_nodes(&self) -> usize {
294 self.edges.len()
295 }
296}
297#[allow(dead_code)]
299pub struct RewriteRuleSet {
300 rules: Vec<RewriteRule>,
301}
302#[allow(dead_code)]
303impl RewriteRuleSet {
304 pub fn new() -> Self {
306 Self { rules: Vec::new() }
307 }
308 pub fn add(&mut self, rule: RewriteRule) {
310 self.rules.push(rule);
311 }
312 pub fn len(&self) -> usize {
314 self.rules.len()
315 }
316 pub fn is_empty(&self) -> bool {
318 self.rules.is_empty()
319 }
320 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
322 self.rules.iter().filter(|r| r.conditional).collect()
323 }
324 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
326 self.rules.iter().filter(|r| !r.conditional).collect()
327 }
328 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
330 self.rules.iter().find(|r| r.name == name)
331 }
332}
333#[allow(dead_code)]
338#[derive(Debug, Clone)]
339pub struct ScopedContext {
340 inner: Context,
342 scope_stack: Vec<ContextSnapshot>,
344}
345impl ScopedContext {
346 #[allow(dead_code)]
348 pub fn new() -> Self {
349 Self {
350 inner: Context::new(),
351 scope_stack: Vec::new(),
352 }
353 }
354 #[allow(dead_code)]
356 pub fn push_scope(&mut self) {
357 self.scope_stack.push(self.inner.save());
358 }
359 #[allow(dead_code)]
361 pub fn pop_scope(&mut self) {
362 if let Some(snap) = self.scope_stack.pop() {
363 self.inner.restore(&snap);
364 }
365 }
366 #[allow(dead_code)]
368 pub fn add_local(&mut self, name: Name, ty: Expr) -> FVarId {
369 self.inner.push_local(name, ty, None)
370 }
371 #[allow(dead_code)]
373 pub fn get_local(&self, fvar: FVarId) -> Option<&LocalVar> {
374 self.inner.get_local(fvar)
375 }
376 #[allow(dead_code)]
378 pub fn scope_depth(&self) -> usize {
379 self.scope_stack.len()
380 }
381 #[allow(dead_code)]
383 pub fn num_locals(&self) -> usize {
384 self.inner.num_locals()
385 }
386 #[allow(dead_code)]
388 pub fn inner(&self) -> &Context {
389 &self.inner
390 }
391 #[allow(dead_code)]
393 pub fn get_fvars(&self) -> Vec<Expr> {
394 self.inner.get_fvars()
395 }
396}
397#[allow(dead_code)]
399#[derive(Debug, Clone)]
400pub struct FreshNameSeq {
401 base: String,
402 counter: u64,
403 used: Vec<String>,
404}
405impl FreshNameSeq {
406 #[allow(dead_code)]
408 pub fn new(base: &str) -> Self {
409 Self {
410 base: base.to_string(),
411 counter: 0,
412 used: Vec::new(),
413 }
414 }
415 #[allow(dead_code)]
417 #[allow(clippy::should_implement_trait)]
418 pub fn next(&mut self) -> Name {
419 loop {
420 let candidate = if self.counter == 0 {
421 self.base.clone()
422 } else {
423 format!("{}_{}", self.base, self.counter)
424 };
425 self.counter += 1;
426 if !self.used.contains(&candidate) {
427 self.used.push(candidate.clone());
428 return Name::str(&candidate);
429 }
430 }
431 }
432 #[allow(dead_code)]
434 pub fn reserve(&mut self, name: &str) {
435 if !self.used.contains(&name.to_string()) {
436 self.used.push(name.to_string());
437 }
438 }
439 #[allow(dead_code)]
441 pub fn count(&self) -> usize {
442 self.used.len()
443 }
444}
445#[allow(dead_code)]
447pub struct Stopwatch {
448 start: crate::wall_clock::Instant,
449 splits: Vec<f64>,
450}
451#[allow(dead_code)]
452impl Stopwatch {
453 pub fn start() -> Self {
455 Self {
456 start: crate::wall_clock::Instant::now(),
457 splits: Vec::new(),
458 }
459 }
460 pub fn split(&mut self) {
462 self.splits.push(self.elapsed_ms());
463 }
464 pub fn elapsed_ms(&self) -> f64 {
466 self.start.elapsed().as_secs_f64() * 1000.0
467 }
468 pub fn splits(&self) -> &[f64] {
470 &self.splits
471 }
472 pub fn num_splits(&self) -> usize {
474 self.splits.len()
475 }
476}
477#[allow(dead_code)]
479#[allow(missing_docs)]
480pub struct RewriteRule {
481 pub name: String,
483 pub lhs: String,
485 pub rhs: String,
487 pub conditional: bool,
489}
490#[allow(dead_code)]
491impl RewriteRule {
492 pub fn unconditional(
494 name: impl Into<String>,
495 lhs: impl Into<String>,
496 rhs: impl Into<String>,
497 ) -> Self {
498 Self {
499 name: name.into(),
500 lhs: lhs.into(),
501 rhs: rhs.into(),
502 conditional: false,
503 }
504 }
505 pub fn conditional(
507 name: impl Into<String>,
508 lhs: impl Into<String>,
509 rhs: impl Into<String>,
510 ) -> Self {
511 Self {
512 name: name.into(),
513 lhs: lhs.into(),
514 rhs: rhs.into(),
515 conditional: true,
516 }
517 }
518 pub fn display(&self) -> String {
520 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
521 }
522}
523#[allow(dead_code)]
525#[derive(Debug, Clone)]
526pub struct HypContext {
527 inner: Context,
528 hyps: Vec<(Name, FVarId)>,
530}
531impl HypContext {
532 #[allow(dead_code)]
534 pub fn new() -> Self {
535 Self {
536 inner: Context::new(),
537 hyps: Vec::new(),
538 }
539 }
540 #[allow(dead_code)]
542 pub fn add_hyp(&mut self, name: Name, ty: Expr) -> FVarId {
543 let fvar = self.inner.push_local(name.clone(), ty, None);
544 self.hyps.push((name, fvar));
545 fvar
546 }
547 #[allow(dead_code)]
549 pub fn find_hyp(&self, name: &Name) -> Option<FVarId> {
550 self.hyps
551 .iter()
552 .rev()
553 .find(|(n, _)| n == name)
554 .map(|(_, id)| *id)
555 }
556 #[allow(dead_code)]
558 pub fn hyp_type(&self, fvar: FVarId) -> Option<&Expr> {
559 self.inner.get_type(fvar)
560 }
561 #[allow(dead_code)]
563 pub fn num_hyps(&self) -> usize {
564 self.hyps.len()
565 }
566 #[allow(dead_code)]
568 pub fn hyp_names(&self) -> Vec<&Name> {
569 self.hyps.iter().map(|(n, _)| n).collect()
570 }
571 #[allow(dead_code)]
573 pub fn remove_last_hyp(&mut self) {
574 if let Some((_, _)) = self.hyps.pop() {
575 self.inner.pop_local();
576 }
577 }
578 #[allow(dead_code)]
580 pub fn clear(&mut self) {
581 self.hyps.clear();
582 self.inner.clear();
583 }
584}
585#[allow(dead_code)]
587pub struct FocusStack<T> {
588 items: Vec<T>,
589}
590#[allow(dead_code)]
591impl<T> FocusStack<T> {
592 pub fn new() -> Self {
594 Self { items: Vec::new() }
595 }
596 pub fn focus(&mut self, item: T) {
598 self.items.push(item);
599 }
600 pub fn blur(&mut self) -> Option<T> {
602 self.items.pop()
603 }
604 pub fn current(&self) -> Option<&T> {
606 self.items.last()
607 }
608 pub fn depth(&self) -> usize {
610 self.items.len()
611 }
612 pub fn is_empty(&self) -> bool {
614 self.items.is_empty()
615 }
616}
617#[allow(dead_code)]
619#[allow(missing_docs)]
620pub enum DecisionNode {
621 Leaf(String),
623 Branch {
625 key: String,
626 val: String,
627 yes_branch: Box<DecisionNode>,
628 no_branch: Box<DecisionNode>,
629 },
630}
631#[allow(dead_code)]
632impl DecisionNode {
633 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
635 match self {
636 DecisionNode::Leaf(action) => action.as_str(),
637 DecisionNode::Branch {
638 key,
639 val,
640 yes_branch,
641 no_branch,
642 } => {
643 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
644 if actual == val.as_str() {
645 yes_branch.evaluate(ctx)
646 } else {
647 no_branch.evaluate(ctx)
648 }
649 }
650 }
651 }
652 pub fn depth(&self) -> usize {
654 match self {
655 DecisionNode::Leaf(_) => 0,
656 DecisionNode::Branch {
657 yes_branch,
658 no_branch,
659 ..
660 } => 1 + yes_branch.depth().max(no_branch.depth()),
661 }
662 }
663}
664#[allow(dead_code)]
666pub struct StatSummary {
667 count: u64,
668 sum: f64,
669 min: f64,
670 max: f64,
671}
672#[allow(dead_code)]
673impl StatSummary {
674 pub fn new() -> Self {
676 Self {
677 count: 0,
678 sum: 0.0,
679 min: f64::INFINITY,
680 max: f64::NEG_INFINITY,
681 }
682 }
683 pub fn record(&mut self, val: f64) {
685 self.count += 1;
686 self.sum += val;
687 if val < self.min {
688 self.min = val;
689 }
690 if val > self.max {
691 self.max = val;
692 }
693 }
694 pub fn mean(&self) -> Option<f64> {
696 if self.count == 0 {
697 None
698 } else {
699 Some(self.sum / self.count as f64)
700 }
701 }
702 pub fn min(&self) -> Option<f64> {
704 if self.count == 0 {
705 None
706 } else {
707 Some(self.min)
708 }
709 }
710 pub fn max(&self) -> Option<f64> {
712 if self.count == 0 {
713 None
714 } else {
715 Some(self.max)
716 }
717 }
718 pub fn count(&self) -> u64 {
720 self.count
721 }
722}
723#[allow(dead_code)]
725pub struct ConfigNode {
726 key: String,
727 value: Option<String>,
728 children: Vec<ConfigNode>,
729}
730#[allow(dead_code)]
731impl ConfigNode {
732 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
734 Self {
735 key: key.into(),
736 value: Some(value.into()),
737 children: Vec::new(),
738 }
739 }
740 pub fn section(key: impl Into<String>) -> Self {
742 Self {
743 key: key.into(),
744 value: None,
745 children: Vec::new(),
746 }
747 }
748 pub fn add_child(&mut self, child: ConfigNode) {
750 self.children.push(child);
751 }
752 pub fn key(&self) -> &str {
754 &self.key
755 }
756 pub fn value(&self) -> Option<&str> {
758 self.value.as_deref()
759 }
760 pub fn num_children(&self) -> usize {
762 self.children.len()
763 }
764 pub fn lookup(&self, path: &str) -> Option<&str> {
766 let mut parts = path.splitn(2, '.');
767 let head = parts.next()?;
768 let tail = parts.next();
769 if head != self.key {
770 return None;
771 }
772 match tail {
773 None => self.value.as_deref(),
774 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
775 }
776 }
777 fn lookup_relative(&self, path: &str) -> Option<&str> {
778 let mut parts = path.splitn(2, '.');
779 let head = parts.next()?;
780 let tail = parts.next();
781 if head != self.key {
782 return None;
783 }
784 match tail {
785 None => self.value.as_deref(),
786 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
787 }
788 }
789}
790#[allow(dead_code)]
792pub struct NonEmptyVec<T> {
793 head: T,
794 tail: Vec<T>,
795}
796#[allow(dead_code)]
797impl<T> NonEmptyVec<T> {
798 pub fn singleton(val: T) -> Self {
800 Self {
801 head: val,
802 tail: Vec::new(),
803 }
804 }
805 pub fn push(&mut self, val: T) {
807 self.tail.push(val);
808 }
809 pub fn first(&self) -> &T {
811 &self.head
812 }
813 pub fn last(&self) -> &T {
815 self.tail.last().unwrap_or(&self.head)
816 }
817 pub fn len(&self) -> usize {
819 1 + self.tail.len()
820 }
821 pub fn is_empty(&self) -> bool {
823 self.len() == 0
824 }
825 pub fn to_vec(&self) -> Vec<&T> {
827 let mut v = vec![&self.head];
828 v.extend(self.tail.iter());
829 v
830 }
831}
832#[derive(Debug, Clone)]
834pub struct Context {
835 locals: Vec<LocalVar>,
837 fvar_map: HashMap<FVarId, usize>,
839 next_fvar: u64,
841}
842impl Context {
843 pub fn new() -> Self {
845 Self {
846 locals: Vec::new(),
847 fvar_map: HashMap::new(),
848 next_fvar: 0,
849 }
850 }
851 pub fn with_start_fvar(start: u64) -> Self {
853 Self {
854 locals: Vec::new(),
855 fvar_map: HashMap::new(),
856 next_fvar: start,
857 }
858 }
859 pub fn fresh_fvar(&mut self) -> FVarId {
861 let fvar = FVarId(self.next_fvar);
862 self.next_fvar += 1;
863 fvar
864 }
865 pub fn push_local(&mut self, name: Name, ty: Expr, val: Option<Expr>) -> FVarId {
867 self.push_local_with_binder(name, BinderInfo::Default, ty, val)
868 }
869 pub fn push_local_with_binder(
871 &mut self,
872 name: Name,
873 binder_info: BinderInfo,
874 ty: Expr,
875 val: Option<Expr>,
876 ) -> FVarId {
877 let fvar = self.fresh_fvar();
878 let index = self.locals.len();
879 self.locals.push(LocalVar {
880 name,
881 binder_info,
882 ty,
883 val,
884 fvar,
885 index,
886 });
887 self.fvar_map.insert(fvar, index);
888 fvar
889 }
890 pub fn mk_local_decl(&mut self, name: Name, binder_info: BinderInfo, ty: Expr) -> Expr {
892 let fvar = self.push_local_with_binder(name, binder_info, ty, None);
893 Expr::FVar(fvar)
894 }
895 pub fn mk_let_decl(&mut self, name: Name, ty: Expr, val: Expr) -> Expr {
897 let fvar = self.push_local(name, ty, Some(val));
898 Expr::FVar(fvar)
899 }
900 pub fn pop_local(&mut self) -> Option<LocalVar> {
902 if let Some(local) = self.locals.pop() {
903 self.fvar_map.remove(&local.fvar);
904 Some(local)
905 } else {
906 None
907 }
908 }
909 pub fn save(&self) -> ContextSnapshot {
911 ContextSnapshot {
912 num_locals: self.locals.len(),
913 next_fvar: self.next_fvar,
914 }
915 }
916 pub fn restore(&mut self, snapshot: &ContextSnapshot) {
918 while self.locals.len() > snapshot.num_locals {
919 self.pop_local();
920 }
921 self.next_fvar = snapshot.next_fvar;
922 }
923 pub fn get_local(&self, fvar: FVarId) -> Option<&LocalVar> {
925 self.fvar_map
926 .get(&fvar)
927 .and_then(|&idx| self.locals.get(idx))
928 }
929 pub fn get_type(&self, fvar: FVarId) -> Option<&Expr> {
931 self.get_local(fvar).map(|l| &l.ty)
932 }
933 pub fn get_value(&self, fvar: FVarId) -> Option<&Expr> {
935 self.get_local(fvar).and_then(|l| l.val.as_ref())
936 }
937 pub fn is_let(&self, fvar: FVarId) -> bool {
939 self.get_local(fvar).is_some_and(|l| l.val.is_some())
940 }
941 pub fn find_local(&self, name: &Name) -> Option<&LocalVar> {
943 self.locals.iter().rev().find(|local| &local.name == name)
944 }
945 pub fn num_locals(&self) -> usize {
947 self.locals.len()
948 }
949 pub fn is_empty(&self) -> bool {
951 self.locals.is_empty()
952 }
953 pub fn all_locals(&self) -> &[LocalVar] {
955 &self.locals
956 }
957 pub fn get_fvars(&self) -> Vec<Expr> {
959 self.locals.iter().map(|l| Expr::FVar(l.fvar)).collect()
960 }
961 pub fn mk_lambda(&self, fvars: &[FVarId], body: Expr) -> Expr {
967 let mut result = body;
968 for &fvar in fvars.iter().rev() {
969 if let Some(local) = self.get_local(fvar) {
970 result = abstract_fvar(result, fvar);
971 result = Expr::Lam(
972 local.binder_info,
973 local.name.clone(),
974 Node::new(abstract_fvars_in_type(local.ty.clone(), fvars, fvar)),
975 Node::new(result),
976 );
977 }
978 }
979 result
980 }
981 pub fn mk_pi(&self, fvars: &[FVarId], body: Expr) -> Expr {
986 let mut result = body;
987 for &fvar in fvars.iter().rev() {
988 if let Some(local) = self.get_local(fvar) {
989 result = abstract_fvar(result, fvar);
990 result = Expr::Pi(
991 local.binder_info,
992 local.name.clone(),
993 Node::new(abstract_fvars_in_type(local.ty.clone(), fvars, fvar)),
994 Node::new(result),
995 );
996 }
997 }
998 result
999 }
1000 pub fn clear(&mut self) {
1002 self.locals.clear();
1003 self.fvar_map.clear();
1004 }
1005 pub fn with_local<F, R>(&mut self, name: Name, ty: Expr, f: F) -> R
1009 where
1010 F: FnOnce(&mut Self, FVarId) -> R,
1011 {
1012 let fvar = self.push_local(name, ty, None);
1013 let result = f(self, fvar);
1014 self.pop_local();
1015 result
1016 }
1017}
1018#[allow(dead_code)]
1020pub struct WriteOnce<T> {
1021 value: std::cell::Cell<Option<T>>,
1022}
1023#[allow(dead_code)]
1024impl<T: Copy> WriteOnce<T> {
1025 pub fn new() -> Self {
1027 Self {
1028 value: std::cell::Cell::new(None),
1029 }
1030 }
1031 pub fn write(&self, val: T) -> bool {
1033 if self.value.get().is_some() {
1034 return false;
1035 }
1036 self.value.set(Some(val));
1037 true
1038 }
1039 pub fn read(&self) -> Option<T> {
1041 self.value.get()
1042 }
1043 pub fn is_written(&self) -> bool {
1045 self.value.get().is_some()
1046 }
1047}
1048#[allow(dead_code)]
1050pub struct SmallMap<K: Ord + Clone, V: Clone> {
1051 entries: Vec<(K, V)>,
1052}
1053#[allow(dead_code)]
1054impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
1055 pub fn new() -> Self {
1057 Self {
1058 entries: Vec::new(),
1059 }
1060 }
1061 pub fn insert(&mut self, key: K, val: V) {
1063 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
1064 Ok(i) => self.entries[i].1 = val,
1065 Err(i) => self.entries.insert(i, (key, val)),
1066 }
1067 }
1068 pub fn get(&self, key: &K) -> Option<&V> {
1070 self.entries
1071 .binary_search_by_key(&key, |(k, _)| k)
1072 .ok()
1073 .map(|i| &self.entries[i].1)
1074 }
1075 pub fn len(&self) -> usize {
1077 self.entries.len()
1078 }
1079 pub fn is_empty(&self) -> bool {
1081 self.entries.is_empty()
1082 }
1083 pub fn keys(&self) -> Vec<&K> {
1085 self.entries.iter().map(|(k, _)| k).collect()
1086 }
1087 pub fn values(&self) -> Vec<&V> {
1089 self.entries.iter().map(|(_, v)| v).collect()
1090 }
1091}
1092#[allow(dead_code)]
1094#[derive(Debug, Clone)]
1095pub struct ContextEntry {
1096 pub name: Name,
1098 pub ty: Expr,
1100 pub val: Option<Expr>,
1102 pub binder_info: BinderInfo,
1104}
1105impl ContextEntry {
1106 #[allow(dead_code)]
1108 pub fn local(name: Name, ty: Expr) -> Self {
1109 Self {
1110 name,
1111 ty,
1112 val: None,
1113 binder_info: BinderInfo::Default,
1114 }
1115 }
1116 #[allow(dead_code)]
1118 pub fn implicit(name: Name, ty: Expr) -> Self {
1119 Self {
1120 name,
1121 ty,
1122 val: None,
1123 binder_info: BinderInfo::Implicit,
1124 }
1125 }
1126 #[allow(dead_code)]
1128 pub fn let_binding(name: Name, ty: Expr, val: Expr) -> Self {
1129 Self {
1130 name,
1131 ty,
1132 val: Some(val),
1133 binder_info: BinderInfo::Default,
1134 }
1135 }
1136 #[allow(dead_code)]
1138 pub fn is_let(&self) -> bool {
1139 self.val.is_some()
1140 }
1141 #[allow(dead_code)]
1143 pub fn is_implicit(&self) -> bool {
1144 matches!(self.binder_info, BinderInfo::Implicit)
1145 }
1146}
1147#[allow(dead_code)]
1149pub struct WindowIterator<'a, T> {
1150 pub(super) data: &'a [T],
1151 pub(super) pos: usize,
1152 pub(super) window: usize,
1153}
1154#[allow(dead_code)]
1155impl<'a, T> WindowIterator<'a, T> {
1156 pub fn new(data: &'a [T], window: usize) -> Self {
1158 Self {
1159 data,
1160 pos: 0,
1161 window,
1162 }
1163 }
1164}
1165#[allow(dead_code)]
1167pub struct SlidingSum {
1168 window: Vec<f64>,
1169 capacity: usize,
1170 pos: usize,
1171 sum: f64,
1172 count: usize,
1173}
1174#[allow(dead_code)]
1175impl SlidingSum {
1176 pub fn new(capacity: usize) -> Self {
1178 Self {
1179 window: vec![0.0; capacity],
1180 capacity,
1181 pos: 0,
1182 sum: 0.0,
1183 count: 0,
1184 }
1185 }
1186 pub fn push(&mut self, val: f64) {
1188 let oldest = self.window[self.pos];
1189 self.sum -= oldest;
1190 self.sum += val;
1191 self.window[self.pos] = val;
1192 self.pos = (self.pos + 1) % self.capacity;
1193 if self.count < self.capacity {
1194 self.count += 1;
1195 }
1196 }
1197 pub fn sum(&self) -> f64 {
1199 self.sum
1200 }
1201 pub fn mean(&self) -> Option<f64> {
1203 if self.count == 0 {
1204 None
1205 } else {
1206 Some(self.sum / self.count as f64)
1207 }
1208 }
1209 pub fn count(&self) -> usize {
1211 self.count
1212 }
1213}
1214#[allow(dead_code)]
1216#[derive(Debug, Clone, Default)]
1217pub struct ContextChain {
1218 entries: Vec<ContextEntry>,
1219}
1220impl ContextChain {
1221 #[allow(dead_code)]
1223 pub fn new() -> Self {
1224 Self::default()
1225 }
1226 #[allow(dead_code)]
1228 pub fn push(&mut self, entry: ContextEntry) {
1229 self.entries.push(entry);
1230 }
1231 #[allow(dead_code)]
1233 pub fn pop(&mut self) -> Option<ContextEntry> {
1234 self.entries.pop()
1235 }
1236 #[allow(dead_code)]
1238 pub fn len(&self) -> usize {
1239 self.entries.len()
1240 }
1241 #[allow(dead_code)]
1243 pub fn is_empty(&self) -> bool {
1244 self.entries.is_empty()
1245 }
1246 #[allow(dead_code)]
1248 pub fn entries(&self) -> &[ContextEntry] {
1249 &self.entries
1250 }
1251 #[allow(dead_code)]
1253 pub fn num_lets(&self) -> usize {
1254 self.entries.iter().filter(|e| e.is_let()).count()
1255 }
1256 #[allow(dead_code)]
1258 pub fn num_implicit(&self) -> usize {
1259 self.entries.iter().filter(|e| e.is_implicit()).count()
1260 }
1261 #[allow(dead_code)]
1263 pub fn find(&self, name: &Name) -> Option<&ContextEntry> {
1264 self.entries.iter().rev().find(|e| &e.name == name)
1265 }
1266 #[allow(dead_code)]
1268 pub fn from_context(ctx: &Context) -> Self {
1269 let mut chain = Self::new();
1270 for local in ctx.all_locals() {
1271 chain.push(ContextEntry {
1272 name: local.name.clone(),
1273 ty: local.ty.clone(),
1274 val: local.val.clone(),
1275 binder_info: local.binder_info,
1276 });
1277 }
1278 chain
1279 }
1280}
1281#[allow(dead_code)]
1283pub struct LabelSet {
1284 labels: Vec<String>,
1285}
1286#[allow(dead_code)]
1287impl LabelSet {
1288 pub fn new() -> Self {
1290 Self { labels: Vec::new() }
1291 }
1292 pub fn add(&mut self, label: impl Into<String>) {
1294 let s = label.into();
1295 if !self.labels.contains(&s) {
1296 self.labels.push(s);
1297 }
1298 }
1299 pub fn has(&self, label: &str) -> bool {
1301 self.labels.iter().any(|l| l == label)
1302 }
1303 pub fn count(&self) -> usize {
1305 self.labels.len()
1306 }
1307 pub fn all(&self) -> &[String] {
1309 &self.labels
1310 }
1311}
1312#[allow(dead_code)]
1314#[derive(Debug, Clone, Default)]
1315pub struct ContextDiff {
1316 pub added: Vec<Name>,
1318 pub removed: Vec<Name>,
1320}
1321impl ContextDiff {
1322 #[allow(dead_code)]
1324 pub fn compute(old: &Context, new: &Context) -> Self {
1325 let old_names: std::collections::HashSet<&Name> =
1326 old.all_locals().iter().map(|l| &l.name).collect();
1327 let new_names: std::collections::HashSet<&Name> =
1328 new.all_locals().iter().map(|l| &l.name).collect();
1329 let added = new_names
1330 .difference(&old_names)
1331 .map(|&n| n.clone())
1332 .collect();
1333 let removed = old_names
1334 .difference(&new_names)
1335 .map(|&n| n.clone())
1336 .collect();
1337 Self { added, removed }
1338 }
1339 #[allow(dead_code)]
1341 pub fn is_empty(&self) -> bool {
1342 self.added.is_empty() && self.removed.is_empty()
1343 }
1344}
1345#[allow(dead_code)]
1347pub struct PathBuf {
1348 components: Vec<String>,
1349}
1350#[allow(dead_code)]
1351impl PathBuf {
1352 pub fn new() -> Self {
1354 Self {
1355 components: Vec::new(),
1356 }
1357 }
1358 pub fn push(&mut self, comp: impl Into<String>) {
1360 self.components.push(comp.into());
1361 }
1362 pub fn pop(&mut self) {
1364 self.components.pop();
1365 }
1366 pub fn as_str(&self) -> String {
1368 self.components.join("/")
1369 }
1370 pub fn depth(&self) -> usize {
1372 self.components.len()
1373 }
1374 pub fn clear(&mut self) {
1376 self.components.clear();
1377 }
1378}
1379#[derive(Debug, Clone)]
1381pub struct NameGenerator {
1382 prefix: String,
1384 next: u64,
1386}
1387impl NameGenerator {
1388 pub fn new(prefix: impl Into<String>) -> Self {
1390 Self {
1391 prefix: prefix.into(),
1392 next: 0,
1393 }
1394 }
1395 #[allow(clippy::should_implement_trait)]
1397 pub fn next(&mut self) -> Name {
1398 let n = self.next;
1399 self.next += 1;
1400 Name::str(format!("{}_{}", self.prefix, n))
1401 }
1402 pub fn next_fvar_id(&mut self) -> FVarId {
1404 let n = self.next;
1405 self.next += 1;
1406 FVarId(n)
1407 }
1408}
1409#[allow(dead_code)]
1411pub struct StackCalc {
1412 stack: Vec<i64>,
1413}
1414#[allow(dead_code)]
1415impl StackCalc {
1416 pub fn new() -> Self {
1418 Self { stack: Vec::new() }
1419 }
1420 pub fn push(&mut self, n: i64) {
1422 self.stack.push(n);
1423 }
1424 fn apply_binary(&mut self, op: impl FnOnce(i64, i64) -> i64) -> Option<i64> {
1428 let (rest_len, a, b) = match self.stack[..] {
1429 [ref rest @ .., a, b] => (rest.len(), a, b),
1430 _ => return None,
1431 };
1432 let value = op(a, b);
1433 self.stack.truncate(rest_len);
1434 self.stack.push(value);
1435 Some(value)
1436 }
1437 pub fn add(&mut self) -> Option<i64> {
1441 self.apply_binary(|a, b| a + b)
1442 }
1443 pub fn sub(&mut self) -> Option<i64> {
1447 self.apply_binary(|a, b| a - b)
1448 }
1449 pub fn mul(&mut self) -> Option<i64> {
1453 self.apply_binary(|a, b| a * b)
1454 }
1455 pub fn peek(&self) -> Option<i64> {
1457 self.stack.last().copied()
1458 }
1459 pub fn depth(&self) -> usize {
1461 self.stack.len()
1462 }
1463}
1464#[allow(dead_code)]
1466#[derive(Debug, Clone, Default)]
1467pub struct ContextStats {
1468 pub num_locals: usize,
1470 pub num_lets: usize,
1472 pub num_implicit: usize,
1474 pub max_depth: usize,
1476}
1477impl ContextStats {
1478 #[allow(dead_code)]
1480 pub fn from_context(ctx: &Context) -> Self {
1481 let locals = ctx.all_locals();
1482 let num_lets = locals.iter().filter(|l| l.val.is_some()).count();
1483 let num_implicit = locals
1484 .iter()
1485 .filter(|l| matches!(l.binder_info, BinderInfo::Implicit))
1486 .count();
1487 Self {
1488 num_locals: locals.len(),
1489 num_lets,
1490 num_implicit,
1491 max_depth: locals.len(),
1492 }
1493 }
1494}
1495#[allow(dead_code)]
1497pub struct RawFnPtr {
1498 ptr: usize,
1500 arity: usize,
1501 name: String,
1502}
1503#[allow(dead_code)]
1504impl RawFnPtr {
1505 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
1507 Self {
1508 ptr,
1509 arity,
1510 name: name.into(),
1511 }
1512 }
1513 pub fn arity(&self) -> usize {
1515 self.arity
1516 }
1517 pub fn name(&self) -> &str {
1519 &self.name
1520 }
1521 pub fn raw(&self) -> usize {
1523 self.ptr
1524 }
1525}
1526#[allow(dead_code)]
1528pub struct TokenBucket {
1529 capacity: u64,
1530 tokens: u64,
1531 refill_per_ms: u64,
1532 last_refill: crate::wall_clock::Instant,
1533}
1534#[allow(dead_code)]
1535impl TokenBucket {
1536 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
1538 Self {
1539 capacity,
1540 tokens: capacity,
1541 refill_per_ms,
1542 last_refill: crate::wall_clock::Instant::now(),
1543 }
1544 }
1545 pub fn try_consume(&mut self, n: u64) -> bool {
1547 self.refill();
1548 if self.tokens >= n {
1549 self.tokens -= n;
1550 true
1551 } else {
1552 false
1553 }
1554 }
1555 fn refill(&mut self) {
1556 let now = crate::wall_clock::Instant::now();
1557 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
1558 if elapsed_ms > 0 {
1559 let new_tokens = elapsed_ms * self.refill_per_ms;
1560 self.tokens = (self.tokens + new_tokens).min(self.capacity);
1561 self.last_refill = now;
1562 }
1563 }
1564 pub fn available(&self) -> u64 {
1566 self.tokens
1567 }
1568 pub fn capacity(&self) -> u64 {
1570 self.capacity
1571 }
1572}
1573#[allow(dead_code)]
1575pub struct FlatSubstitution {
1576 pairs: Vec<(String, String)>,
1577}
1578#[allow(dead_code)]
1579impl FlatSubstitution {
1580 pub fn new() -> Self {
1582 Self { pairs: Vec::new() }
1583 }
1584 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
1586 self.pairs.push((from.into(), to.into()));
1587 }
1588 pub fn apply(&self, s: &str) -> String {
1590 let mut result = s.to_string();
1591 for (from, to) in &self.pairs {
1592 result = result.replace(from.as_str(), to.as_str());
1593 }
1594 result
1595 }
1596 pub fn len(&self) -> usize {
1598 self.pairs.len()
1599 }
1600 pub fn is_empty(&self) -> bool {
1602 self.pairs.is_empty()
1603 }
1604}
1605#[allow(dead_code)]
1607pub struct VersionedRecord<T: Clone> {
1608 earlier: Vec<T>,
1610 current: T,
1612}
1613#[allow(dead_code)]
1614impl<T: Clone> VersionedRecord<T> {
1615 pub fn new(initial: T) -> Self {
1617 Self {
1618 earlier: Vec::new(),
1619 current: initial,
1620 }
1621 }
1622 pub fn update(&mut self, val: T) {
1624 let previous = std::mem::replace(&mut self.current, val);
1625 self.earlier.push(previous);
1626 }
1627 pub fn current(&self) -> &T {
1629 &self.current
1630 }
1631 pub fn at_version(&self, n: usize) -> Option<&T> {
1633 match self.earlier.get(n) {
1634 Some(value) => Some(value),
1635 None if n == self.earlier.len() => Some(&self.current),
1636 None => None,
1637 }
1638 }
1639 pub fn version(&self) -> usize {
1641 self.earlier.len()
1642 }
1643 pub fn has_history(&self) -> bool {
1645 !self.earlier.is_empty()
1646 }
1647}