1use crate::declaration::{ConstructorVal, InductiveVal};
6use crate::def_eq::DefEqChecker;
7use crate::error::KernelError;
8use crate::expr_util::{get_app_args, get_app_fn, has_any_fvar, mk_app};
9use crate::instantiate::instantiate_type_lparams;
10use crate::reduce::{Reducer, TransparencyMode};
11use crate::subst::{abstract_expr, instantiate};
12use crate::Node;
13use crate::{BinderInfo, Environment, Expr, FVarId, Level, Literal, Name};
14use std::rc::Rc;
15
16use std::collections::HashMap;
17
18#[allow(dead_code)]
20pub struct SimpleDag {
21 edges: Vec<Vec<usize>>,
23}
24#[allow(dead_code)]
25impl SimpleDag {
26 pub fn new(n: usize) -> Self {
28 Self {
29 edges: vec![Vec::new(); n],
30 }
31 }
32 pub fn add_edge(&mut self, from: usize, to: usize) {
34 if from < self.edges.len() {
35 self.edges[from].push(to);
36 }
37 }
38 pub fn successors(&self, node: usize) -> &[usize] {
40 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
41 }
42 pub fn can_reach(&self, from: usize, to: usize) -> bool {
44 let mut visited = vec![false; self.edges.len()];
45 self.dfs(from, to, &mut visited)
46 }
47 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
48 if cur == target {
49 return true;
50 }
51 if cur >= visited.len() || visited[cur] {
52 return false;
53 }
54 visited[cur] = true;
55 for &next in self.successors(cur) {
56 if self.dfs(next, target, visited) {
57 return true;
58 }
59 }
60 false
61 }
62 pub fn topological_sort(&self) -> Option<Vec<usize>> {
64 let n = self.edges.len();
65 let mut in_degree = vec![0usize; n];
66 for succs in &self.edges {
67 for &s in succs {
68 if s < n {
69 in_degree[s] += 1;
70 }
71 }
72 }
73 let mut queue: std::collections::VecDeque<usize> =
74 (0..n).filter(|&i| in_degree[i] == 0).collect();
75 let mut order = Vec::new();
76 while let Some(node) = queue.pop_front() {
77 order.push(node);
78 for &s in self.successors(node) {
79 if s < n {
80 in_degree[s] -= 1;
81 if in_degree[s] == 0 {
82 queue.push_back(s);
83 }
84 }
85 }
86 }
87 if order.len() == n {
88 Some(order)
89 } else {
90 None
91 }
92 }
93 pub fn num_nodes(&self) -> usize {
95 self.edges.len()
96 }
97}
98#[allow(dead_code)]
100pub struct TransitiveClosure {
101 adj: Vec<Vec<usize>>,
102 n: usize,
103}
104#[allow(dead_code)]
105impl TransitiveClosure {
106 pub fn new(n: usize) -> Self {
108 Self {
109 adj: vec![Vec::new(); n],
110 n,
111 }
112 }
113 pub fn add_edge(&mut self, from: usize, to: usize) {
115 if from < self.n {
116 self.adj[from].push(to);
117 }
118 }
119 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
121 let mut visited = vec![false; self.n];
122 let mut queue = std::collections::VecDeque::new();
123 queue.push_back(start);
124 while let Some(node) = queue.pop_front() {
125 if node >= self.n || visited[node] {
126 continue;
127 }
128 visited[node] = true;
129 for &next in &self.adj[node] {
130 queue.push_back(next);
131 }
132 }
133 (0..self.n).filter(|&i| visited[i]).collect()
134 }
135 pub fn can_reach(&self, from: usize, to: usize) -> bool {
137 self.reachable_from(from).contains(&to)
138 }
139}
140#[allow(dead_code)]
142pub struct ConfigNode {
143 key: String,
144 value: Option<String>,
145 children: Vec<ConfigNode>,
146}
147#[allow(dead_code)]
148impl ConfigNode {
149 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
151 Self {
152 key: key.into(),
153 value: Some(value.into()),
154 children: Vec::new(),
155 }
156 }
157 pub fn section(key: impl Into<String>) -> Self {
159 Self {
160 key: key.into(),
161 value: None,
162 children: Vec::new(),
163 }
164 }
165 pub fn add_child(&mut self, child: ConfigNode) {
167 self.children.push(child);
168 }
169 pub fn key(&self) -> &str {
171 &self.key
172 }
173 pub fn value(&self) -> Option<&str> {
175 self.value.as_deref()
176 }
177 pub fn num_children(&self) -> usize {
179 self.children.len()
180 }
181 pub fn lookup(&self, path: &str) -> Option<&str> {
183 let mut parts = path.splitn(2, '.');
184 let head = parts.next()?;
185 let tail = parts.next();
186 if head != self.key {
187 return None;
188 }
189 match tail {
190 None => self.value.as_deref(),
191 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
192 }
193 }
194 fn lookup_relative(&self, path: &str) -> Option<&str> {
195 let mut parts = path.splitn(2, '.');
196 let head = parts.next()?;
197 let tail = parts.next();
198 if head != self.key {
199 return None;
200 }
201 match tail {
202 None => self.value.as_deref(),
203 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
204 }
205 }
206}
207#[allow(dead_code)]
209#[derive(Debug, Clone)]
210pub struct TypingJudgment {
211 pub expr: Expr,
213 pub ty: Expr,
215 pub success: bool,
217}
218impl TypingJudgment {
219 #[allow(dead_code)]
221 pub fn ok(expr: Expr, ty: Expr) -> Self {
222 Self {
223 expr,
224 ty,
225 success: true,
226 }
227 }
228 #[allow(dead_code)]
230 pub fn fail(expr: Expr) -> Self {
231 Self {
232 ty: Expr::Sort(Level::zero()),
233 expr,
234 success: false,
235 }
236 }
237 #[allow(dead_code)]
239 pub fn is_ok(&self) -> bool {
240 self.success
241 }
242}
243#[allow(dead_code)]
245pub struct SparseVec<T: Default + Clone + PartialEq> {
246 entries: std::collections::HashMap<usize, T>,
247 default_: T,
248 logical_len: usize,
249}
250#[allow(dead_code)]
251impl<T: Default + Clone + PartialEq> SparseVec<T> {
252 pub fn new(len: usize) -> Self {
254 Self {
255 entries: std::collections::HashMap::new(),
256 default_: T::default(),
257 logical_len: len,
258 }
259 }
260 pub fn set(&mut self, idx: usize, val: T) {
262 if val == self.default_ {
263 self.entries.remove(&idx);
264 } else {
265 self.entries.insert(idx, val);
266 }
267 }
268 pub fn get(&self, idx: usize) -> &T {
270 self.entries.get(&idx).unwrap_or(&self.default_)
271 }
272 pub fn len(&self) -> usize {
274 self.logical_len
275 }
276 pub fn is_empty(&self) -> bool {
278 self.len() == 0
279 }
280 pub fn nnz(&self) -> usize {
282 self.entries.len()
283 }
284}
285#[allow(dead_code)]
287pub struct StackCalc {
288 stack: Vec<i64>,
289}
290#[allow(dead_code)]
291impl StackCalc {
292 pub fn new() -> Self {
294 Self { stack: Vec::new() }
295 }
296 pub fn push(&mut self, n: i64) {
298 self.stack.push(n);
299 }
300 fn apply_binary(&mut self, op: impl FnOnce(i64, i64) -> i64) -> Option<i64> {
304 let (rest_len, a, b) = match self.stack[..] {
305 [ref rest @ .., a, b] => (rest.len(), a, b),
306 _ => return None,
307 };
308 let value = op(a, b);
309 self.stack.truncate(rest_len);
310 self.stack.push(value);
311 Some(value)
312 }
313 pub fn add(&mut self) -> Option<i64> {
317 self.apply_binary(|a, b| a + b)
318 }
319 pub fn sub(&mut self) -> Option<i64> {
323 self.apply_binary(|a, b| a - b)
324 }
325 pub fn mul(&mut self) -> Option<i64> {
329 self.apply_binary(|a, b| a * b)
330 }
331 pub fn peek(&self) -> Option<i64> {
333 self.stack.last().copied()
334 }
335 pub fn depth(&self) -> usize {
337 self.stack.len()
338 }
339}
340#[allow(dead_code)]
342pub struct WindowIterator<'a, T> {
343 pub(super) data: &'a [T],
344 pub(super) pos: usize,
345 pub(super) window: usize,
346}
347#[allow(dead_code)]
348impl<'a, T> WindowIterator<'a, T> {
349 pub fn new(data: &'a [T], window: usize) -> Self {
351 Self {
352 data,
353 pos: 0,
354 window,
355 }
356 }
357}
358#[allow(dead_code)]
360#[derive(Debug, Clone)]
361pub struct InferCacheEntry {
362 pub expr: Expr,
364 pub ty: Expr,
366}
367#[allow(dead_code)]
369#[allow(missing_docs)]
370pub struct RewriteRule {
371 pub name: String,
373 pub lhs: String,
375 pub rhs: String,
377 pub conditional: bool,
379}
380#[allow(dead_code)]
381impl RewriteRule {
382 pub fn unconditional(
384 name: impl Into<String>,
385 lhs: impl Into<String>,
386 rhs: impl Into<String>,
387 ) -> Self {
388 Self {
389 name: name.into(),
390 lhs: lhs.into(),
391 rhs: rhs.into(),
392 conditional: false,
393 }
394 }
395 pub fn conditional(
397 name: impl Into<String>,
398 lhs: impl Into<String>,
399 rhs: impl Into<String>,
400 ) -> Self {
401 Self {
402 name: name.into(),
403 lhs: lhs.into(),
404 rhs: rhs.into(),
405 conditional: true,
406 }
407 }
408 pub fn display(&self) -> String {
410 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
411 }
412}
413#[allow(dead_code)]
415pub struct RewriteRuleSet {
416 rules: Vec<RewriteRule>,
417}
418#[allow(dead_code)]
419impl RewriteRuleSet {
420 pub fn new() -> Self {
422 Self { rules: Vec::new() }
423 }
424 pub fn add(&mut self, rule: RewriteRule) {
426 self.rules.push(rule);
427 }
428 pub fn len(&self) -> usize {
430 self.rules.len()
431 }
432 pub fn is_empty(&self) -> bool {
434 self.rules.is_empty()
435 }
436 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
438 self.rules.iter().filter(|r| r.conditional).collect()
439 }
440 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
442 self.rules.iter().filter(|r| !r.conditional).collect()
443 }
444 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
446 self.rules.iter().find(|r| r.name == name)
447 }
448}
449#[allow(dead_code)]
451pub struct Stopwatch {
452 start: crate::wall_clock::Instant,
453 splits: Vec<f64>,
454}
455#[allow(dead_code)]
456impl Stopwatch {
457 pub fn start() -> Self {
459 Self {
460 start: crate::wall_clock::Instant::now(),
461 splits: Vec::new(),
462 }
463 }
464 pub fn split(&mut self) {
466 self.splits.push(self.elapsed_ms());
467 }
468 pub fn elapsed_ms(&self) -> f64 {
470 self.start.elapsed().as_secs_f64() * 1000.0
471 }
472 pub fn splits(&self) -> &[f64] {
474 &self.splits
475 }
476 pub fn num_splits(&self) -> usize {
478 self.splits.len()
479 }
480}
481#[derive(Clone, Debug, Default)]
483pub struct InferStats {
484 pub infer_calls: usize,
486 pub whnf_calls: usize,
488 pub def_eq_calls: usize,
490 pub const_lookups: usize,
492 pub cache_hits: usize,
494}
495impl InferStats {
496 pub fn reset(&mut self) {
498 *self = InferStats::default();
499 }
500 pub fn total_ops(&self) -> usize {
502 self.infer_calls + self.whnf_calls + self.def_eq_calls
503 }
504}
505#[allow(dead_code)]
507pub struct FocusStack<T> {
508 items: Vec<T>,
509}
510#[allow(dead_code)]
511impl<T> FocusStack<T> {
512 pub fn new() -> Self {
514 Self { items: Vec::new() }
515 }
516 pub fn focus(&mut self, item: T) {
518 self.items.push(item);
519 }
520 pub fn blur(&mut self) -> Option<T> {
522 self.items.pop()
523 }
524 pub fn current(&self) -> Option<&T> {
526 self.items.last()
527 }
528 pub fn depth(&self) -> usize {
530 self.items.len()
531 }
532 pub fn is_empty(&self) -> bool {
534 self.items.is_empty()
535 }
536}
537#[allow(dead_code)]
539pub struct NonEmptyVec<T> {
540 head: T,
541 tail: Vec<T>,
542}
543#[allow(dead_code)]
544impl<T> NonEmptyVec<T> {
545 pub fn singleton(val: T) -> Self {
547 Self {
548 head: val,
549 tail: Vec::new(),
550 }
551 }
552 pub fn push(&mut self, val: T) {
554 self.tail.push(val);
555 }
556 pub fn first(&self) -> &T {
558 &self.head
559 }
560 pub fn last(&self) -> &T {
562 self.tail.last().unwrap_or(&self.head)
563 }
564 pub fn len(&self) -> usize {
566 1 + self.tail.len()
567 }
568 pub fn is_empty(&self) -> bool {
570 self.len() == 0
571 }
572 pub fn to_vec(&self) -> Vec<&T> {
574 let mut v = vec![&self.head];
575 v.extend(self.tail.iter());
576 v
577 }
578}
579#[allow(dead_code)]
581pub struct TransformStat {
582 before: StatSummary,
583 after: StatSummary,
584}
585#[allow(dead_code)]
586impl TransformStat {
587 pub fn new() -> Self {
589 Self {
590 before: StatSummary::new(),
591 after: StatSummary::new(),
592 }
593 }
594 pub fn record_before(&mut self, v: f64) {
596 self.before.record(v);
597 }
598 pub fn record_after(&mut self, v: f64) {
600 self.after.record(v);
601 }
602 pub fn mean_ratio(&self) -> Option<f64> {
604 let b = self.before.mean()?;
605 let a = self.after.mean()?;
606 if b.abs() < f64::EPSILON {
607 return None;
608 }
609 Some(a / b)
610 }
611}
612#[allow(dead_code)]
614pub struct TokenBucket {
615 capacity: u64,
616 tokens: u64,
617 refill_per_ms: u64,
618 last_refill: crate::wall_clock::Instant,
619}
620#[allow(dead_code)]
621impl TokenBucket {
622 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
624 Self {
625 capacity,
626 tokens: capacity,
627 refill_per_ms,
628 last_refill: crate::wall_clock::Instant::now(),
629 }
630 }
631 pub fn try_consume(&mut self, n: u64) -> bool {
633 self.refill();
634 if self.tokens >= n {
635 self.tokens -= n;
636 true
637 } else {
638 false
639 }
640 }
641 fn refill(&mut self) {
642 let now = crate::wall_clock::Instant::now();
643 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
644 if elapsed_ms > 0 {
645 let new_tokens = elapsed_ms * self.refill_per_ms;
646 self.tokens = (self.tokens + new_tokens).min(self.capacity);
647 self.last_refill = now;
648 }
649 }
650 pub fn available(&self) -> u64 {
652 self.tokens
653 }
654 pub fn capacity(&self) -> u64 {
656 self.capacity
657 }
658}
659#[allow(dead_code)]
661pub struct FlatSubstitution {
662 pairs: Vec<(String, String)>,
663}
664#[allow(dead_code)]
665impl FlatSubstitution {
666 pub fn new() -> Self {
668 Self { pairs: Vec::new() }
669 }
670 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
672 self.pairs.push((from.into(), to.into()));
673 }
674 pub fn apply(&self, s: &str) -> String {
676 let mut result = s.to_string();
677 for (from, to) in &self.pairs {
678 result = result.replace(from.as_str(), to.as_str());
679 }
680 result
681 }
682 pub fn len(&self) -> usize {
684 self.pairs.len()
685 }
686 pub fn is_empty(&self) -> bool {
688 self.pairs.is_empty()
689 }
690}
691#[allow(dead_code)]
693#[derive(Debug, Clone, Copy, PartialEq, Eq)]
694pub enum TypeKind {
695 Prop,
697 Type0,
699 LargeType,
701 Universe,
703 Pi,
705 Lambda,
707 Application,
709 FreeVar,
711 Constant,
713 Literal,
715 Unknown,
717}
718#[allow(dead_code)]
720pub struct WriteOnce<T> {
721 value: std::cell::Cell<Option<T>>,
722}
723#[allow(dead_code)]
724impl<T: Copy> WriteOnce<T> {
725 pub fn new() -> Self {
727 Self {
728 value: std::cell::Cell::new(None),
729 }
730 }
731 pub fn write(&self, val: T) -> bool {
733 if self.value.get().is_some() {
734 return false;
735 }
736 self.value.set(Some(val));
737 true
738 }
739 pub fn read(&self) -> Option<T> {
741 self.value.get()
742 }
743 pub fn is_written(&self) -> bool {
745 self.value.get().is_some()
746 }
747}
748pub struct TypeChecker<'env> {
753 env: &'env Environment,
754 local_ctx: Vec<LocalDecl>,
755 reducer: Reducer,
756 def_eq_checker: DefEqChecker<'env>,
757 next_fvar: u64,
758 check_mode: bool,
760 pub(super) infer_cache: crate::term_cache::TermCache<Expr>,
764}
765impl<'env> TypeChecker<'env> {
766 pub fn new(env: &'env Environment) -> Self {
768 Self {
769 env,
770 local_ctx: Vec::new(),
771 reducer: Reducer::new(),
772 def_eq_checker: DefEqChecker::new(env),
773 next_fvar: 0,
774 check_mode: true,
775 infer_cache: crate::term_cache::TermCache::new(),
776 }
777 }
778 pub fn new_infer_only(env: &'env Environment) -> Self {
780 Self {
781 env,
782 local_ctx: Vec::new(),
783 reducer: Reducer::new(),
784 def_eq_checker: DefEqChecker::new(env),
785 next_fvar: 0,
786 check_mode: false,
787 infer_cache: crate::term_cache::TermCache::new(),
788 }
789 }
790 pub fn with_fvar_types(
807 env: &'env Environment,
808 locals: &std::collections::HashMap<u64, Expr>,
809 ) -> Self {
810 use crate::def_eq::types::DEF_EQ_OPENED_FVAR_BASE;
811
812 let mut tc = Self::new(env);
813 let mut ids: Vec<u64> = locals.keys().copied().collect();
814 ids.sort_unstable();
815 let mut max_own: Option<u64> = None;
816 let mut max_opened: Option<u64> = None;
817 for id in ids {
818 if let Some(ty) = locals.get(&id) {
819 tc.push_local(LocalDecl {
820 fvar: FVarId(id),
821 name: Name::anonymous(),
822 ty: ty.clone(),
823 val: None,
824 });
825 }
826 if id < DEF_EQ_OPENED_FVAR_BASE {
829 max_own = Some(id);
830 } else {
831 max_opened = Some(id);
832 }
833 }
834 tc.next_fvar = max_own.map_or(0, |m| m + 1);
835 if let Some(m) = max_opened {
836 tc.def_eq_checker.reserve_opened_fvars_through(m);
837 }
838 tc
839 }
840 pub(crate) fn with_local_types(
853 env: &'env Environment,
854 locals: &crate::local_types::LocalTypes,
855 ) -> Self {
856 let mut tc = Self::with_fvar_types(env, locals.live());
857 if let Some(m) = locals.max_own_id() {
858 tc.next_fvar = tc.next_fvar.max(m.saturating_add(1));
859 }
860 if let Some(m) = locals.max_opened_id() {
861 tc.def_eq_checker.reserve_opened_fvars_through(m);
862 }
863 tc
864 }
865 #[cfg(test)]
869 pub(crate) fn local_mirrors(&self) -> ([&crate::local_types::LocalTypes; 3], u64) {
870 let (def_eq, def_eq_reducer, next_opened) = self.def_eq_checker.local_types();
871 (
872 [self.reducer.local_types(), def_eq, def_eq_reducer],
873 next_opened,
874 )
875 }
876 pub fn set_transparency(&mut self, mode: TransparencyMode) {
882 self.reducer.set_transparency(mode);
883 self.def_eq_checker.set_transparency(mode);
884 self.infer_cache.clear();
885 }
886 fn mirror_local(&mut self, fvar: FVarId, ty: &Expr) {
892 self.def_eq_checker.record_fvar_type(fvar, ty.clone());
893 if self.reducer.bind_fvar_type(fvar, ty.clone()) {
894 self.infer_cache.clear();
895 }
896 }
897 pub fn env(&self) -> &Environment {
899 self.env
900 }
901 pub fn fresh_fvar(&mut self, name: Name, ty: Expr) -> FVarId {
903 let fvar = FVarId(self.next_fvar);
904 self.next_fvar += 1;
905 self.mirror_local(fvar, &ty);
911 self.local_ctx.push(LocalDecl {
912 fvar,
913 name,
914 ty,
915 val: None,
916 });
917 fvar
918 }
919 pub fn fresh_fvar_let(&mut self, name: Name, ty: Expr, val: Expr) -> FVarId {
921 let fvar = FVarId(self.next_fvar);
922 self.next_fvar += 1;
923 self.mirror_local(fvar, &ty);
924 self.local_ctx.push(LocalDecl {
925 fvar,
926 name,
927 ty,
928 val: Some(val),
929 });
930 fvar
931 }
932 pub fn push_local(&mut self, decl: LocalDecl) {
934 self.mirror_local(decl.fvar, &decl.ty);
935 self.local_ctx.push(decl);
936 }
937 pub fn pop_local(&mut self) -> Option<LocalDecl> {
945 let decl = self.local_ctx.pop()?;
946 if !self.local_ctx.iter().any(|other| other.fvar == decl.fvar) {
947 self.def_eq_checker.forget_fvar_type(decl.fvar);
948 self.reducer.forget_fvar_type(decl.fvar);
949 }
950 Some(decl)
951 }
952 #[allow(clippy::result_large_err)]
954 fn lookup_fvar(&self, fvar: FVarId) -> Result<&LocalDecl, KernelError> {
955 self.local_ctx
956 .iter()
957 .find(|decl| decl.fvar == fvar)
958 .ok_or_else(|| KernelError::Other(format!("free variable not found: {:?}", fvar)))
959 }
960 pub fn local_ctx(&self) -> &[LocalDecl] {
962 &self.local_ctx
963 }
964 pub fn whnf(&mut self, expr: &Expr) -> Expr {
966 self.reducer.whnf_env(expr, self.env)
967 }
968 #[allow(clippy::result_large_err)]
972 pub fn ensure_sort(&mut self, expr: &Expr) -> Result<Level, KernelError> {
973 let ty = self.infer_type(expr)?;
974 let ty_whnf = self.whnf(&ty);
975 match ty_whnf {
976 Expr::Sort(l) => Ok(l),
977 _ => Err(KernelError::NotASort(ty_whnf)),
978 }
979 }
980 #[allow(clippy::result_large_err)]
982 pub fn ensure_pi(&mut self, expr: &Expr) -> Result<Expr, KernelError> {
983 let ty = self.infer_type(expr)?;
984 let ty_whnf = self.whnf(&ty);
985 if ty_whnf.is_pi() {
986 Ok(ty_whnf)
987 } else {
988 Err(KernelError::NotAFunction(ty_whnf))
989 }
990 }
991 pub fn is_def_eq(&mut self, t: &Expr, s: &Expr) -> bool {
993 self.def_eq_checker.is_def_eq(t, s)
994 }
995 #[allow(clippy::result_large_err)]
997 pub fn check_type(
998 &mut self,
999 expr: &Expr,
1000 inferred: &Expr,
1001 expected: &Expr,
1002 ) -> Result<(), KernelError> {
1003 if self.is_def_eq(inferred, expected) {
1004 Ok(())
1005 } else {
1006 Err(KernelError::TypeMismatch {
1007 expected: expected.clone(),
1008 got: inferred.clone(),
1009 context: format!("checking {}", expr),
1010 })
1011 }
1012 }
1013 #[allow(clippy::result_large_err)]
1016 pub(super) fn infer_type_uncached(&mut self, expr: &Expr) -> Result<Expr, KernelError> {
1017 match expr {
1018 Expr::Sort(l) => Ok(Expr::Sort(Level::succ(l.clone()))),
1019 Expr::BVar(idx) => Err(KernelError::UnboundVariable(*idx)),
1020 Expr::FVar(fvar) => {
1021 let decl = self.lookup_fvar(*fvar)?;
1022 Ok(decl.ty.clone())
1023 }
1024 Expr::Const(name, levels) => self.infer_const(name, levels),
1025 Expr::App(f, a) => self.infer_app(f, a),
1026 Expr::Lam(bi, name, ty, body) => {
1027 if self.check_mode {
1028 self.ensure_sort(ty)?;
1029 }
1030 let fvar = self.fresh_fvar(name.clone(), (**ty).clone());
1031 let body_open = instantiate(body, &Expr::FVar(fvar));
1032 let body_ty = self.infer_type(&body_open)?;
1033 self.pop_local();
1034 let body_ty_closed = abstract_expr(&body_ty, fvar);
1035 Ok(Expr::Pi(
1036 *bi,
1037 name.clone(),
1038 ty.clone(),
1039 Node::new(body_ty_closed),
1040 ))
1041 }
1042 Expr::Pi(_, _, dom, cod) => {
1043 let dom_sort = self.ensure_sort(dom)?;
1044 let fvar = self.fresh_fvar(Name::str("_"), (**dom).clone());
1045 let cod_open = instantiate(cod, &Expr::FVar(fvar));
1046 let cod_sort = self.ensure_sort(&cod_open)?;
1047 self.pop_local();
1048 Ok(Expr::Sort(crate::level::mk_imax(dom_sort, cod_sort)))
1055 }
1056 Expr::Let(_, ty, val, body) => {
1057 if self.check_mode {
1058 self.ensure_sort(ty)?;
1059 let val_ty = self.infer_type(val)?;
1060 self.check_type(val, &val_ty, ty)?;
1061 }
1062 let body_inst = instantiate(body, val);
1063 self.infer_type(&body_inst)
1064 }
1065 Expr::Lit(Literal::Nat(_)) => Ok(Expr::Const(Name::str("Nat"), vec![])),
1066 Expr::Lit(Literal::Str(_)) => Ok(Expr::Const(Name::str("String"), vec![])),
1067 Expr::Proj(struct_name, idx, struct_expr) => {
1068 self.infer_proj(struct_name, *idx, struct_expr)
1069 }
1070 }
1071 }
1072 #[allow(clippy::result_large_err)]
1081 fn infer_const(&self, name: &Name, levels: &[Level]) -> Result<Expr, KernelError> {
1082 if let Some(ci) = self.env.find(name) {
1083 return Self::instantiate_const_type(name, ci.level_params(), ci.ty(), levels);
1084 }
1085 let decl = self
1086 .env
1087 .get(name)
1088 .ok_or_else(|| KernelError::UnknownConstant(name.clone()))?;
1089 Self::instantiate_const_type(name, decl.univ_params(), decl.ty(), levels)
1090 }
1091 #[allow(clippy::result_large_err)]
1095 fn instantiate_const_type(
1096 name: &Name,
1097 params: &[Name],
1098 ty: &Expr,
1099 levels: &[Level],
1100 ) -> Result<Expr, KernelError> {
1101 if params.len() != levels.len() {
1102 return Err(KernelError::Other(format!(
1103 "universe parameter count mismatch for {}: expected {}, got {}",
1104 name,
1105 params.len(),
1106 levels.len()
1107 )));
1108 }
1109 if params.is_empty() {
1110 return Ok(ty.clone());
1112 }
1113 Ok(instantiate_type_lparams(ty, params, levels))
1114 }
1115 #[allow(clippy::result_large_err)]
1117 fn infer_app(&mut self, f: &Expr, a: &Expr) -> Result<Expr, KernelError> {
1118 let f_ty = self.infer_type(f)?;
1119 let f_ty_whnf = self.whnf(&f_ty);
1120 match &f_ty_whnf {
1121 Expr::Pi(_, _, dom, cod) => {
1122 if self.check_mode {
1123 let a_ty = self.infer_type(a)?;
1124 self.check_type(a, &a_ty, dom)?;
1125 }
1126 Ok(instantiate(cod, a))
1127 }
1128 _ => Err(KernelError::NotAFunction(f_ty_whnf)),
1129 }
1130 }
1131 #[allow(clippy::result_large_err)]
1133 fn infer_proj(
1134 &mut self,
1135 struct_name: &Name,
1136 idx: u32,
1137 struct_expr: &Expr,
1138 ) -> Result<Expr, KernelError> {
1139 let ind_val = self
1140 .env
1141 .get_inductive_val(struct_name)
1142 .ok_or_else(|| KernelError::Other(format!("not a structure type: {}", struct_name)))?
1143 .clone();
1144 if !self.env.is_structure_like(struct_name) {
1145 return Err(KernelError::Other(format!(
1146 "invalid projection: {} is not structure-like \
1147 (requires exactly one constructor, no indices, and no recursion; \
1148 has {} constructors, {} indices, is_rec = {})",
1149 struct_name,
1150 ind_val.ctors.len(),
1151 ind_val.num_indices,
1152 ind_val.is_rec
1153 )));
1154 }
1155 let ctor_name = &ind_val.ctors[0];
1156 let ctor_val = self
1157 .env
1158 .get_constructor_val(ctor_name)
1159 .ok_or_else(|| KernelError::Other(format!("constructor not found: {}", ctor_name)))?
1160 .clone();
1161 if idx >= ctor_val.num_fields {
1162 return Err(KernelError::Other(format!(
1163 "field index {} out of range for {} (has {} fields)",
1164 idx, struct_name, ctor_val.num_fields
1165 )));
1166 }
1167 let struct_ty = self.infer_type(struct_expr)?;
1168 self.infer_proj_field_type(&ind_val, &ctor_val, idx, struct_expr, &struct_ty)
1169 }
1170 #[allow(clippy::result_large_err)]
1182 fn infer_proj_field_type(
1183 &mut self,
1184 ind_val: &InductiveVal,
1185 ctor_val: &ConstructorVal,
1186 idx: u32,
1187 struct_expr: &Expr,
1188 struct_ty: &Expr,
1189 ) -> Result<Expr, KernelError> {
1190 let ctor_ty = ctor_val.common.ty.clone();
1191 let struct_ty_whnf = self.whnf(struct_ty);
1192 let levels: Vec<Level> = match get_app_fn(&struct_ty_whnf) {
1193 Expr::Const(name, lvls) if *name == ind_val.common.name => lvls.clone(),
1194 _ => {
1195 return Err(KernelError::Other(format!(
1196 "invalid projection: expected an element of {}, but the operand has type {}",
1197 ind_val.common.name, struct_ty_whnf
1198 )))
1199 }
1200 };
1201 let level_params = &ind_val.common.level_params;
1202 let mut cur_ty = if level_params.is_empty() || levels.is_empty() {
1203 ctor_ty
1204 } else {
1205 instantiate_type_lparams(&ctor_ty, level_params, &levels)
1206 };
1207 let struct_args: Vec<Expr> = get_app_args(&struct_ty_whnf).into_iter().cloned().collect();
1208 if struct_args.len() != ind_val.num_params as usize {
1209 return Err(KernelError::Other(format!(
1210 "invalid projection: {} expects {} parameters, but the operand type {} supplies {}",
1211 ind_val.common.name,
1212 ind_val.num_params,
1213 struct_ty_whnf,
1214 struct_args.len()
1215 )));
1216 }
1217 for param in &struct_args {
1218 match cur_ty {
1219 Expr::Pi(_, _, _, body) => {
1220 cur_ty = instantiate(&body, param);
1221 }
1222 _ => {
1223 return Err(KernelError::Other(format!(
1224 "invalid projection: constructor {} telescope ended while \
1225 instantiating the parameters of {}",
1226 ctor_val.common.name, ind_val.common.name
1227 )))
1228 }
1229 }
1230 }
1231 for j in 0..idx {
1232 match cur_ty {
1233 Expr::Pi(_, _, _, body) => {
1234 let field_val = Expr::Proj(
1235 ind_val.common.name.clone(),
1236 j,
1237 Node::new(struct_expr.clone()),
1238 );
1239 cur_ty = instantiate(&body, &field_val);
1240 }
1241 _ => {
1242 return Err(KernelError::Other(format!(
1243 "invalid projection: constructor {} telescope ended at field {} \
1244 while computing field {} of {}",
1245 ctor_val.common.name, j, idx, ind_val.common.name
1246 )))
1247 }
1248 }
1249 }
1250 match cur_ty {
1251 Expr::Pi(_, _, dom, _) => Ok((*dom).clone()),
1252 _ => Err(KernelError::Other(format!(
1253 "invalid projection: constructor {} telescope has no field {} for {}",
1254 ctor_val.common.name, idx, ind_val.common.name
1255 ))),
1256 }
1257 }
1258 pub fn is_prop(&mut self, expr: &Expr) -> bool {
1260 if let Ok(ty) = self.infer_type(expr) {
1261 let ty_whnf = self.whnf(&ty);
1262 matches!(ty_whnf, Expr::Sort(l) if l.is_zero())
1263 } else {
1264 false
1265 }
1266 }
1267 pub fn is_proof(&mut self, expr: &Expr) -> bool {
1269 if let Ok(ty) = self.infer_type(expr) {
1270 self.is_prop(&ty)
1271 } else {
1272 false
1273 }
1274 }
1275 pub fn is_type(&mut self, expr: &Expr) -> bool {
1277 if let Ok(ty) = self.infer_type(expr) {
1278 let ty_whnf = self.whnf(&ty);
1279 ty_whnf.is_sort()
1280 } else {
1281 false
1282 }
1283 }
1284 #[allow(clippy::result_large_err)]
1286 pub fn get_level(&mut self, expr: &Expr) -> Result<Level, KernelError> {
1287 let ty = self.infer_type(expr)?;
1288 let ty_whnf = self.whnf(&ty);
1289 match ty_whnf {
1290 Expr::Sort(l) => Ok(l),
1291 _ => Err(KernelError::NotASort(ty_whnf)),
1292 }
1293 }
1294 pub fn unfold_definition(&mut self, expr: &Expr) -> Option<Expr> {
1296 let head = get_app_fn(expr);
1297 if let Expr::Const(name, levels) = head {
1298 if let Some(ci) = self.env.find(name) {
1299 if let Some(val) = ci.value() {
1300 let hint = ci.reducibility_hint();
1301 if hint.should_unfold() {
1302 let val_inst = if ci.level_params().is_empty() || levels.is_empty() {
1303 val.clone()
1304 } else {
1305 instantiate_type_lparams(val, ci.level_params(), levels)
1306 };
1307 let args: Vec<Expr> = get_app_args(expr).into_iter().cloned().collect();
1308 return Some(mk_app(val_inst, &args));
1309 }
1310 }
1311 }
1312 }
1313 None
1314 }
1315}
1316impl<'env> TypeChecker<'env> {
1317 #[allow(clippy::result_large_err)]
1319 pub fn infer_app_chain(
1320 &mut self,
1321 f: &Expr,
1322 args: &[Expr],
1323 ) -> Result<Expr, crate::error::KernelError> {
1324 let mut ty = self.infer_type(f)?;
1325 for arg in args {
1326 let whnf = self.whnf(&ty);
1327 match whnf {
1328 Expr::Pi(_, _, dom, cod) => {
1329 if self.check_mode {
1330 let arg_ty = self.infer_type(arg)?;
1331 if !self.is_def_eq(&arg_ty, &dom) {
1332 return Err(crate::error::KernelError::TypeMismatch {
1333 expected: (*dom).clone(),
1334 got: arg_ty,
1335 context: "application argument".to_string(),
1336 });
1337 }
1338 }
1339 ty = instantiate(&cod, arg);
1340 }
1341 other => return Err(crate::error::KernelError::NotAFunction(other)),
1342 }
1343 }
1344 Ok(ty)
1345 }
1346 pub fn telescope_type(&mut self, ty: &Expr, max_pis: usize) -> (Vec<LocalDecl>, Expr) {
1348 let mut fvars = Vec::new();
1349 let mut current = ty.clone();
1350 for _ in 0..max_pis {
1351 let whnf = self.whnf(¤t);
1352 match whnf {
1353 Expr::Pi(bi, name, dom, cod) => {
1354 let fvar_id = self.fresh_fvar(name.clone(), (*dom).clone());
1355 let decl = LocalDecl {
1356 fvar: fvar_id,
1357 name,
1358 ty: (*dom).clone(),
1359 val: None,
1360 };
1361 let body = instantiate(&cod, &Expr::FVar(fvar_id));
1362 fvars.push(decl);
1363 current = body;
1364 let _ = bi;
1365 }
1366 _ => break,
1367 }
1368 }
1369 (fvars, current)
1370 }
1371 pub fn close_type_over_fvars(&mut self, fvars: &[LocalDecl], ty: Expr) -> Expr {
1373 let mut result = ty;
1374 for decl in fvars.iter().rev() {
1375 result = abstract_expr(&result, decl.fvar);
1376 result = Expr::Pi(
1377 crate::BinderInfo::Default,
1378 decl.name.clone(),
1379 Node::new(decl.ty.clone()),
1380 Node::new(result),
1381 );
1382 }
1383 result
1384 }
1385 pub fn close_term_over_fvars(&mut self, fvars: &[LocalDecl], term: Expr) -> Expr {
1387 let mut result = term;
1388 for decl in fvars.iter().rev() {
1389 result = abstract_expr(&result, decl.fvar);
1390 result = Expr::Lam(
1391 crate::BinderInfo::Default,
1392 decl.name.clone(),
1393 Node::new(decl.ty.clone()),
1394 Node::new(result),
1395 );
1396 }
1397 result
1398 }
1399 #[allow(clippy::result_large_err)]
1401 pub fn check(&mut self, expr: &Expr, expected: &Expr) -> Result<(), crate::error::KernelError> {
1402 let inferred = self.infer_type(expr)?;
1403 if self.is_def_eq(&inferred, expected) {
1404 Ok(())
1405 } else {
1406 Err(crate::error::KernelError::TypeMismatch {
1407 expected: expected.clone(),
1408 got: inferred,
1409 context: format!("check({:?})", expr),
1410 })
1411 }
1412 }
1413 pub fn try_check(&mut self, expr: &Expr, expected: &Expr) -> bool {
1415 if let Ok(inferred) = self.infer_type(expr) {
1416 self.is_def_eq(&inferred, expected)
1417 } else {
1418 false
1419 }
1420 }
1421 pub fn count_pi_binders(&mut self, ty: &Expr) -> usize {
1423 let mut count = 0;
1424 let mut current = ty.clone();
1425 loop {
1426 let whnf = self.whnf(¤t);
1427 if let Expr::Pi(_, _, _, cod) = whnf {
1428 count += 1;
1429 current = (*cod).clone();
1430 } else {
1431 break;
1432 }
1433 }
1434 count
1435 }
1436 #[allow(clippy::result_large_err)]
1438 pub fn verify_declaration(
1439 &mut self,
1440 name: &Name,
1441 ty: &Expr,
1442 val: Option<&Expr>,
1443 ) -> Result<(), crate::error::KernelError> {
1444 self.ensure_sort(ty)?;
1445 if let Some(v) = val {
1446 let v_ty = self.infer_type(v)?;
1447 if !self.is_def_eq(&v_ty, ty) {
1448 return Err(crate::error::KernelError::TypeMismatch {
1449 expected: ty.clone(),
1450 got: v_ty,
1451 context: format!("verifying declaration {}", name),
1452 });
1453 }
1454 }
1455 Ok(())
1456 }
1457 pub fn normalize(&mut self, expr: &Expr) -> Expr {
1459 let whnf = self.whnf(expr);
1460 match &whnf {
1461 Expr::App(f, a) => {
1462 let f_norm = self.normalize(f);
1463 let a_norm = self.normalize(a);
1464 Expr::App(Node::new(f_norm), Node::new(a_norm))
1465 }
1466 Expr::Lam(bi, name, ty, body) => {
1467 let ty_norm = self.normalize(ty);
1468 let body_norm = self.normalize(body);
1469 Expr::Lam(*bi, name.clone(), Node::new(ty_norm), Node::new(body_norm))
1470 }
1471 Expr::Pi(bi, name, ty, body) => {
1472 let ty_norm = self.normalize(ty);
1473 let body_norm = self.normalize(body);
1474 Expr::Pi(*bi, name.clone(), Node::new(ty_norm), Node::new(body_norm))
1475 }
1476 Expr::Let(name, ty, val, body) => {
1477 let ty_norm = self.normalize(ty);
1478 let val_norm = self.normalize(val);
1479 let body_norm = self.normalize(body);
1480 Expr::Let(
1481 name.clone(),
1482 Node::new(ty_norm),
1483 Node::new(val_norm),
1484 Node::new(body_norm),
1485 )
1486 }
1487 Expr::Proj(sname, idx, inner) => {
1488 let inner_norm = self.normalize(inner);
1489 Expr::Proj(sname.clone(), *idx, Node::new(inner_norm))
1490 }
1491 _ => whnf,
1492 }
1493 }
1494 pub fn constant_arity(&mut self, name: &Name) -> Option<usize> {
1496 let ty = if let Some(ci) = self.env.find(name) {
1497 ci.ty().clone()
1498 } else {
1499 self.env.get(name)?.ty().clone()
1500 };
1501 Some(self.count_pi_binders(&ty))
1502 }
1503 pub fn is_level_eq(&self, l1: &Level, l2: &Level) -> bool {
1510 crate::level::is_equivalent(l1, l2)
1511 }
1512}
1513#[allow(dead_code)]
1515pub struct SmallMap<K: Ord + Clone, V: Clone> {
1516 entries: Vec<(K, V)>,
1517}
1518#[allow(dead_code)]
1519impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
1520 pub fn new() -> Self {
1522 Self {
1523 entries: Vec::new(),
1524 }
1525 }
1526 pub fn insert(&mut self, key: K, val: V) {
1528 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
1529 Ok(i) => self.entries[i].1 = val,
1530 Err(i) => self.entries.insert(i, (key, val)),
1531 }
1532 }
1533 pub fn get(&self, key: &K) -> Option<&V> {
1535 self.entries
1536 .binary_search_by_key(&key, |(k, _)| k)
1537 .ok()
1538 .map(|i| &self.entries[i].1)
1539 }
1540 pub fn len(&self) -> usize {
1542 self.entries.len()
1543 }
1544 pub fn is_empty(&self) -> bool {
1546 self.entries.is_empty()
1547 }
1548 pub fn keys(&self) -> Vec<&K> {
1550 self.entries.iter().map(|(k, _)| k).collect()
1551 }
1552 pub fn values(&self) -> Vec<&V> {
1554 self.entries.iter().map(|(_, v)| v).collect()
1555 }
1556}
1557#[allow(dead_code)]
1559pub struct VersionedRecord<T: Clone> {
1560 earlier: Vec<T>,
1562 current: T,
1564}
1565#[allow(dead_code)]
1566impl<T: Clone> VersionedRecord<T> {
1567 pub fn new(initial: T) -> Self {
1569 Self {
1570 earlier: Vec::new(),
1571 current: initial,
1572 }
1573 }
1574 pub fn update(&mut self, val: T) {
1576 let previous = std::mem::replace(&mut self.current, val);
1577 self.earlier.push(previous);
1578 }
1579 pub fn current(&self) -> &T {
1581 &self.current
1582 }
1583 pub fn at_version(&self, n: usize) -> Option<&T> {
1585 match self.earlier.get(n) {
1586 Some(value) => Some(value),
1587 None if n == self.earlier.len() => Some(&self.current),
1588 None => None,
1589 }
1590 }
1591 pub fn version(&self) -> usize {
1593 self.earlier.len()
1594 }
1595 pub fn has_history(&self) -> bool {
1597 !self.earlier.is_empty()
1598 }
1599}
1600#[allow(dead_code)]
1604pub struct InferCache {
1605 entries: Vec<InferCacheEntry>,
1606 capacity: usize,
1607}
1608impl InferCache {
1609 #[allow(dead_code)]
1611 pub fn new(capacity: usize) -> Self {
1612 Self {
1613 entries: Vec::with_capacity(capacity),
1614 capacity,
1615 }
1616 }
1617 #[allow(dead_code)]
1619 pub fn get(&self, expr: &Expr) -> Option<&Expr> {
1620 self.entries
1621 .iter()
1622 .rev()
1623 .find(|e| &e.expr == expr)
1624 .map(|e| &e.ty)
1625 }
1626 #[allow(dead_code)]
1628 pub fn insert(&mut self, expr: Expr, ty: Expr) {
1629 if self.entries.len() >= self.capacity {
1630 self.entries.remove(0);
1631 }
1632 self.entries.push(InferCacheEntry { expr, ty });
1633 }
1634 #[allow(dead_code)]
1636 pub fn clear(&mut self) {
1637 self.entries.clear();
1638 }
1639 #[allow(dead_code)]
1641 pub fn len(&self) -> usize {
1642 self.entries.len()
1643 }
1644 #[allow(dead_code)]
1646 pub fn is_empty(&self) -> bool {
1647 self.entries.is_empty()
1648 }
1649}
1650#[allow(dead_code)]
1652pub struct SlidingSum {
1653 window: Vec<f64>,
1654 capacity: usize,
1655 pos: usize,
1656 sum: f64,
1657 count: usize,
1658}
1659#[allow(dead_code)]
1660impl SlidingSum {
1661 pub fn new(capacity: usize) -> Self {
1663 Self {
1664 window: vec![0.0; capacity],
1665 capacity,
1666 pos: 0,
1667 sum: 0.0,
1668 count: 0,
1669 }
1670 }
1671 pub fn push(&mut self, val: f64) {
1673 let oldest = self.window[self.pos];
1674 self.sum -= oldest;
1675 self.sum += val;
1676 self.window[self.pos] = val;
1677 self.pos = (self.pos + 1) % self.capacity;
1678 if self.count < self.capacity {
1679 self.count += 1;
1680 }
1681 }
1682 pub fn sum(&self) -> f64 {
1684 self.sum
1685 }
1686 pub fn mean(&self) -> Option<f64> {
1688 if self.count == 0 {
1689 None
1690 } else {
1691 Some(self.sum / self.count as f64)
1692 }
1693 }
1694 pub fn count(&self) -> usize {
1696 self.count
1697 }
1698}
1699#[derive(Clone, Debug)]
1701pub struct LocalDecl {
1702 pub fvar: FVarId,
1704 pub name: Name,
1706 pub ty: Expr,
1708 pub val: Option<Expr>,
1710}
1711#[allow(dead_code)]
1713pub struct StringPool {
1714 free: Vec<String>,
1715}
1716#[allow(dead_code)]
1717impl StringPool {
1718 pub fn new() -> Self {
1720 Self { free: Vec::new() }
1721 }
1722 pub fn take(&mut self) -> String {
1724 self.free.pop().unwrap_or_default()
1725 }
1726 pub fn give(&mut self, mut s: String) {
1728 s.clear();
1729 self.free.push(s);
1730 }
1731 pub fn free_count(&self) -> usize {
1733 self.free.len()
1734 }
1735}
1736#[allow(dead_code)]
1738#[allow(missing_docs)]
1739pub enum DecisionNode {
1740 Leaf(String),
1742 Branch {
1744 key: String,
1745 val: String,
1746 yes_branch: Box<DecisionNode>,
1747 no_branch: Box<DecisionNode>,
1748 },
1749}
1750#[allow(dead_code)]
1751impl DecisionNode {
1752 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
1754 match self {
1755 DecisionNode::Leaf(action) => action.as_str(),
1756 DecisionNode::Branch {
1757 key,
1758 val,
1759 yes_branch,
1760 no_branch,
1761 } => {
1762 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
1763 if actual == val.as_str() {
1764 yes_branch.evaluate(ctx)
1765 } else {
1766 no_branch.evaluate(ctx)
1767 }
1768 }
1769 }
1770 }
1771 pub fn depth(&self) -> usize {
1773 match self {
1774 DecisionNode::Leaf(_) => 0,
1775 DecisionNode::Branch {
1776 yes_branch,
1777 no_branch,
1778 ..
1779 } => 1 + yes_branch.depth().max(no_branch.depth()),
1780 }
1781 }
1782}
1783#[allow(dead_code)]
1785pub struct StatSummary {
1786 count: u64,
1787 sum: f64,
1788 min: f64,
1789 max: f64,
1790}
1791#[allow(dead_code)]
1792impl StatSummary {
1793 pub fn new() -> Self {
1795 Self {
1796 count: 0,
1797 sum: 0.0,
1798 min: f64::INFINITY,
1799 max: f64::NEG_INFINITY,
1800 }
1801 }
1802 pub fn record(&mut self, val: f64) {
1804 self.count += 1;
1805 self.sum += val;
1806 if val < self.min {
1807 self.min = val;
1808 }
1809 if val > self.max {
1810 self.max = val;
1811 }
1812 }
1813 pub fn mean(&self) -> Option<f64> {
1815 if self.count == 0 {
1816 None
1817 } else {
1818 Some(self.sum / self.count as f64)
1819 }
1820 }
1821 pub fn min(&self) -> Option<f64> {
1823 if self.count == 0 {
1824 None
1825 } else {
1826 Some(self.min)
1827 }
1828 }
1829 pub fn max(&self) -> Option<f64> {
1831 if self.count == 0 {
1832 None
1833 } else {
1834 Some(self.max)
1835 }
1836 }
1837 pub fn count(&self) -> u64 {
1839 self.count
1840 }
1841}
1842#[allow(dead_code)]
1844pub struct LabelSet {
1845 labels: Vec<String>,
1846}
1847#[allow(dead_code)]
1848impl LabelSet {
1849 pub fn new() -> Self {
1851 Self { labels: Vec::new() }
1852 }
1853 pub fn add(&mut self, label: impl Into<String>) {
1855 let s = label.into();
1856 if !self.labels.contains(&s) {
1857 self.labels.push(s);
1858 }
1859 }
1860 pub fn has(&self, label: &str) -> bool {
1862 self.labels.iter().any(|l| l == label)
1863 }
1864 pub fn count(&self) -> usize {
1866 self.labels.len()
1867 }
1868 pub fn all(&self) -> &[String] {
1870 &self.labels
1871 }
1872}
1873#[allow(dead_code)]
1875pub struct PathBuf {
1876 components: Vec<String>,
1877}
1878#[allow(dead_code)]
1879impl PathBuf {
1880 pub fn new() -> Self {
1882 Self {
1883 components: Vec::new(),
1884 }
1885 }
1886 pub fn push(&mut self, comp: impl Into<String>) {
1888 self.components.push(comp.into());
1889 }
1890 pub fn pop(&mut self) {
1892 self.components.pop();
1893 }
1894 pub fn as_str(&self) -> String {
1896 self.components.join("/")
1897 }
1898 pub fn depth(&self) -> usize {
1900 self.components.len()
1901 }
1902 pub fn clear(&mut self) {
1904 self.components.clear();
1905 }
1906}
1907#[allow(dead_code)]
1909pub struct RawFnPtr {
1910 ptr: usize,
1912 arity: usize,
1913 name: String,
1914}
1915#[allow(dead_code)]
1916impl RawFnPtr {
1917 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
1919 Self {
1920 ptr,
1921 arity,
1922 name: name.into(),
1923 }
1924 }
1925 pub fn arity(&self) -> usize {
1927 self.arity
1928 }
1929 pub fn name(&self) -> &str {
1931 &self.name
1932 }
1933 pub fn raw(&self) -> usize {
1935 self.ptr
1936 }
1937}
1938#[allow(dead_code)]
1940pub enum Either2<A, B> {
1941 First(A),
1943 Second(B),
1945}
1946#[allow(dead_code)]
1947impl<A, B> Either2<A, B> {
1948 pub fn is_first(&self) -> bool {
1950 matches!(self, Either2::First(_))
1951 }
1952 pub fn is_second(&self) -> bool {
1954 matches!(self, Either2::Second(_))
1955 }
1956 pub fn first(self) -> Option<A> {
1958 match self {
1959 Either2::First(a) => Some(a),
1960 _ => None,
1961 }
1962 }
1963 pub fn second(self) -> Option<B> {
1965 match self {
1966 Either2::Second(b) => Some(b),
1967 _ => None,
1968 }
1969 }
1970 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
1972 match self {
1973 Either2::First(a) => Either2::First(f(a)),
1974 Either2::Second(b) => Either2::Second(b),
1975 }
1976 }
1977}