1use crate::{Expr, Level, Name};
6
7use std::collections::HashMap;
8
9#[allow(dead_code)]
11pub struct Stopwatch {
12 start: crate::wall_clock::Instant,
13 splits: Vec<f64>,
14}
15#[allow(dead_code)]
16impl Stopwatch {
17 pub fn start() -> Self {
19 Self {
20 start: crate::wall_clock::Instant::now(),
21 splits: Vec::new(),
22 }
23 }
24 pub fn split(&mut self) {
26 self.splits.push(self.elapsed_ms());
27 }
28 pub fn elapsed_ms(&self) -> f64 {
30 self.start.elapsed().as_secs_f64() * 1000.0
31 }
32 pub fn splits(&self) -> &[f64] {
34 &self.splits
35 }
36 pub fn num_splits(&self) -> usize {
38 self.splits.len()
39 }
40}
41#[allow(dead_code)]
43pub struct RawFnPtr {
44 ptr: usize,
46 arity: usize,
47 name: String,
48}
49#[allow(dead_code)]
50impl RawFnPtr {
51 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
53 Self {
54 ptr,
55 arity,
56 name: name.into(),
57 }
58 }
59 pub fn arity(&self) -> usize {
61 self.arity
62 }
63 pub fn name(&self) -> &str {
65 &self.name
66 }
67 pub fn raw(&self) -> usize {
69 self.ptr
70 }
71}
72#[allow(dead_code)]
74pub struct TransformStat {
75 before: StatSummary,
76 after: StatSummary,
77}
78#[allow(dead_code)]
79impl TransformStat {
80 pub fn new() -> Self {
82 Self {
83 before: StatSummary::new(),
84 after: StatSummary::new(),
85 }
86 }
87 pub fn record_before(&mut self, v: f64) {
89 self.before.record(v);
90 }
91 pub fn record_after(&mut self, v: f64) {
93 self.after.record(v);
94 }
95 pub fn mean_ratio(&self) -> Option<f64> {
97 let b = self.before.mean()?;
98 let a = self.after.mean()?;
99 if b.abs() < f64::EPSILON {
100 return None;
101 }
102 Some(a / b)
103 }
104}
105#[allow(dead_code)]
107#[allow(missing_docs)]
108pub struct RewriteRule {
109 pub name: String,
111 pub lhs: String,
113 pub rhs: String,
115 pub conditional: bool,
117}
118#[allow(dead_code)]
119impl RewriteRule {
120 pub fn unconditional(
122 name: impl Into<String>,
123 lhs: impl Into<String>,
124 rhs: impl Into<String>,
125 ) -> Self {
126 Self {
127 name: name.into(),
128 lhs: lhs.into(),
129 rhs: rhs.into(),
130 conditional: false,
131 }
132 }
133 pub fn conditional(
135 name: impl Into<String>,
136 lhs: impl Into<String>,
137 rhs: impl Into<String>,
138 ) -> Self {
139 Self {
140 name: name.into(),
141 lhs: lhs.into(),
142 rhs: rhs.into(),
143 conditional: true,
144 }
145 }
146 pub fn display(&self) -> String {
148 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
149 }
150}
151#[allow(dead_code)]
153pub struct StatSummary {
154 count: u64,
155 sum: f64,
156 min: f64,
157 max: f64,
158}
159#[allow(dead_code)]
160impl StatSummary {
161 pub fn new() -> Self {
163 Self {
164 count: 0,
165 sum: 0.0,
166 min: f64::INFINITY,
167 max: f64::NEG_INFINITY,
168 }
169 }
170 pub fn record(&mut self, val: f64) {
172 self.count += 1;
173 self.sum += val;
174 if val < self.min {
175 self.min = val;
176 }
177 if val > self.max {
178 self.max = val;
179 }
180 }
181 pub fn mean(&self) -> Option<f64> {
183 if self.count == 0 {
184 None
185 } else {
186 Some(self.sum / self.count as f64)
187 }
188 }
189 pub fn min(&self) -> Option<f64> {
191 if self.count == 0 {
192 None
193 } else {
194 Some(self.min)
195 }
196 }
197 pub fn max(&self) -> Option<f64> {
199 if self.count == 0 {
200 None
201 } else {
202 Some(self.max)
203 }
204 }
205 pub fn count(&self) -> u64 {
207 self.count
208 }
209}
210#[allow(dead_code)]
212pub struct FocusStack<T> {
213 items: Vec<T>,
214}
215#[allow(dead_code)]
216impl<T> FocusStack<T> {
217 pub fn new() -> Self {
219 Self { items: Vec::new() }
220 }
221 pub fn focus(&mut self, item: T) {
223 self.items.push(item);
224 }
225 pub fn blur(&mut self) -> Option<T> {
227 self.items.pop()
228 }
229 pub fn current(&self) -> Option<&T> {
231 self.items.last()
232 }
233 pub fn depth(&self) -> usize {
235 self.items.len()
236 }
237 pub fn is_empty(&self) -> bool {
239 self.items.is_empty()
240 }
241}
242#[derive(Clone, Debug)]
244pub enum KernelError {
245 TypeMismatch {
247 expected: Expr,
249 got: Expr,
251 context: String,
253 },
254 UnboundVariable(u32),
256 UnknownConstant(Name),
258 UniverseInconsistency {
260 lhs: Level,
262 rhs: Level,
264 },
265 InvalidInductive(String),
267 InvalidRecursor(String),
269 NotASort(Expr),
271 NotAFunction(Expr),
273 InductiveError(String),
275 UnsupportedNestedInductive(Name),
280 Other(String),
282}
283impl KernelError {
284 pub fn category(&self) -> ErrorCategory {
286 match self {
287 KernelError::UnboundVariable(_) => ErrorCategory::Binding,
288 KernelError::UniverseInconsistency { .. } => ErrorCategory::Universe,
289 KernelError::TypeMismatch { .. }
290 | KernelError::NotASort(_)
291 | KernelError::NotAFunction(_) => ErrorCategory::TypeCheck,
292 KernelError::InvalidInductive(_)
293 | KernelError::InvalidRecursor(_)
294 | KernelError::InductiveError(_)
295 | KernelError::UnsupportedNestedInductive(_) => ErrorCategory::Inductive,
296 KernelError::UnknownConstant(_) => ErrorCategory::Resolution,
297 KernelError::Other(_) => ErrorCategory::Other,
298 }
299 }
300 pub fn is_recoverable(&self) -> bool {
302 matches!(
303 self,
304 KernelError::UnknownConstant(_) | KernelError::Other(_)
305 )
306 }
307 pub fn is_fatal(&self) -> bool {
309 !self.is_recoverable()
310 }
311 pub fn with_context(self, ctx: impl Into<String>) -> Self {
313 match self {
314 KernelError::TypeMismatch {
315 expected,
316 got,
317 context,
318 } => {
319 let new_ctx = format!("{} > {}", ctx.into(), context);
320 KernelError::TypeMismatch {
321 expected,
322 got,
323 context: new_ctx,
324 }
325 }
326 other => KernelError::Other(format!("{}: {}", ctx.into(), other)),
327 }
328 }
329 pub fn short_description(&self) -> String {
331 match self {
332 KernelError::TypeMismatch { context, .. } => {
333 format!("type mismatch in {}", context)
334 }
335 KernelError::UnboundVariable(idx) => format!("unbound variable #{}", idx),
336 KernelError::UnknownConstant(name) => format!("unknown constant '{}'", name),
337 KernelError::UniverseInconsistency { .. } => "universe inconsistency".to_string(),
338 KernelError::InvalidInductive(msg) => format!("invalid inductive: {}", msg),
339 KernelError::InvalidRecursor(msg) => format!("invalid recursor: {}", msg),
340 KernelError::NotASort(_) => "expected a sort".to_string(),
341 KernelError::NotAFunction(_) => "expected a function type".to_string(),
342 KernelError::InductiveError(msg) => format!("inductive error: {}", msg),
343 KernelError::UnsupportedNestedInductive(name) => {
344 format!("unsupported: nested inductive type '{}'", name)
345 }
346 KernelError::Other(msg) => msg.clone(),
347 }
348 }
349 pub fn type_mismatch(expected: Expr, got: Expr, context: impl Into<String>) -> Self {
351 KernelError::TypeMismatch {
352 expected,
353 got,
354 context: context.into(),
355 }
356 }
357 pub fn unknown(name: Name) -> Self {
359 KernelError::UnknownConstant(name)
360 }
361 pub fn universe(lhs: Level, rhs: Level) -> Self {
363 KernelError::UniverseInconsistency { lhs, rhs }
364 }
365}
366#[derive(Clone, Debug, Default)]
368pub struct DiagnosticCollection {
369 pub(super) diagnostics: Vec<Diagnostic>,
370}
371impl DiagnosticCollection {
372 pub fn new() -> Self {
374 Self::default()
375 }
376 pub fn add(&mut self, d: Diagnostic) {
378 self.diagnostics.push(d);
379 }
380 pub fn add_error(&mut self, err: &KernelError) {
382 self.add(Diagnostic::from_error(err));
383 }
384 pub fn has_errors(&self) -> bool {
386 self.diagnostics
387 .iter()
388 .any(|d| d.severity == Severity::Error)
389 }
390 pub fn is_empty(&self) -> bool {
392 self.diagnostics.is_empty()
393 }
394 pub fn len(&self) -> usize {
396 self.diagnostics.len()
397 }
398 pub fn iter(&self) -> impl Iterator<Item = &Diagnostic> {
400 self.diagnostics.iter()
401 }
402 pub fn by_severity(&self, severity: Severity) -> Vec<&Diagnostic> {
404 self.diagnostics
405 .iter()
406 .filter(|d| d.severity == severity)
407 .collect()
408 }
409 pub fn errors(&self) -> Vec<&Diagnostic> {
411 self.by_severity(Severity::Error)
412 }
413 pub fn warnings(&self) -> Vec<&Diagnostic> {
415 self.by_severity(Severity::Warning)
416 }
417}
418#[allow(dead_code)]
420pub struct NonEmptyVec<T> {
421 head: T,
422 tail: Vec<T>,
423}
424#[allow(dead_code)]
425impl<T> NonEmptyVec<T> {
426 pub fn singleton(val: T) -> Self {
428 Self {
429 head: val,
430 tail: Vec::new(),
431 }
432 }
433 pub fn push(&mut self, val: T) {
435 self.tail.push(val);
436 }
437 pub fn first(&self) -> &T {
439 &self.head
440 }
441 pub fn last(&self) -> &T {
443 self.tail.last().unwrap_or(&self.head)
444 }
445 pub fn len(&self) -> usize {
447 1 + self.tail.len()
448 }
449 pub fn is_empty(&self) -> bool {
451 self.len() == 0
452 }
453 pub fn to_vec(&self) -> Vec<&T> {
455 let mut v = vec![&self.head];
456 v.extend(self.tail.iter());
457 v
458 }
459}
460#[allow(dead_code)]
462pub struct FlatSubstitution {
463 pairs: Vec<(String, String)>,
464}
465#[allow(dead_code)]
466impl FlatSubstitution {
467 pub fn new() -> Self {
469 Self { pairs: Vec::new() }
470 }
471 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
473 self.pairs.push((from.into(), to.into()));
474 }
475 pub fn apply(&self, s: &str) -> String {
477 let mut result = s.to_string();
478 for (from, to) in &self.pairs {
479 result = result.replace(from.as_str(), to.as_str());
480 }
481 result
482 }
483 pub fn len(&self) -> usize {
485 self.pairs.len()
486 }
487 pub fn is_empty(&self) -> bool {
489 self.pairs.is_empty()
490 }
491}
492#[allow(dead_code)]
494pub struct LabelSet {
495 labels: Vec<String>,
496}
497#[allow(dead_code)]
498impl LabelSet {
499 pub fn new() -> Self {
501 Self { labels: Vec::new() }
502 }
503 pub fn add(&mut self, label: impl Into<String>) {
505 let s = label.into();
506 if !self.labels.contains(&s) {
507 self.labels.push(s);
508 }
509 }
510 pub fn has(&self, label: &str) -> bool {
512 self.labels.iter().any(|l| l == label)
513 }
514 pub fn count(&self) -> usize {
516 self.labels.len()
517 }
518 pub fn all(&self) -> &[String] {
520 &self.labels
521 }
522}
523#[allow(dead_code)]
525pub struct SparseVec<T: Default + Clone + PartialEq> {
526 entries: std::collections::HashMap<usize, T>,
527 default_: T,
528 logical_len: usize,
529}
530#[allow(dead_code)]
531impl<T: Default + Clone + PartialEq> SparseVec<T> {
532 pub fn new(len: usize) -> Self {
534 Self {
535 entries: std::collections::HashMap::new(),
536 default_: T::default(),
537 logical_len: len,
538 }
539 }
540 pub fn set(&mut self, idx: usize, val: T) {
542 if val == self.default_ {
543 self.entries.remove(&idx);
544 } else {
545 self.entries.insert(idx, val);
546 }
547 }
548 pub fn get(&self, idx: usize) -> &T {
550 self.entries.get(&idx).unwrap_or(&self.default_)
551 }
552 pub fn len(&self) -> usize {
554 self.logical_len
555 }
556 pub fn is_empty(&self) -> bool {
558 self.len() == 0
559 }
560 pub fn nnz(&self) -> usize {
562 self.entries.len()
563 }
564}
565#[allow(dead_code)]
567pub struct SmallMap<K: Ord + Clone, V: Clone> {
568 entries: Vec<(K, V)>,
569}
570#[allow(dead_code)]
571impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
572 pub fn new() -> Self {
574 Self {
575 entries: Vec::new(),
576 }
577 }
578 pub fn insert(&mut self, key: K, val: V) {
580 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
581 Ok(i) => self.entries[i].1 = val,
582 Err(i) => self.entries.insert(i, (key, val)),
583 }
584 }
585 pub fn get(&self, key: &K) -> Option<&V> {
587 self.entries
588 .binary_search_by_key(&key, |(k, _)| k)
589 .ok()
590 .map(|i| &self.entries[i].1)
591 }
592 pub fn len(&self) -> usize {
594 self.entries.len()
595 }
596 pub fn is_empty(&self) -> bool {
598 self.entries.is_empty()
599 }
600 pub fn keys(&self) -> Vec<&K> {
602 self.entries.iter().map(|(k, _)| k).collect()
603 }
604 pub fn values(&self) -> Vec<&V> {
606 self.entries.iter().map(|(_, v)| v).collect()
607 }
608}
609#[allow(dead_code)]
611pub struct SlidingSum {
612 window: Vec<f64>,
613 capacity: usize,
614 pos: usize,
615 sum: f64,
616 count: usize,
617}
618#[allow(dead_code)]
619impl SlidingSum {
620 pub fn new(capacity: usize) -> Self {
622 Self {
623 window: vec![0.0; capacity],
624 capacity,
625 pos: 0,
626 sum: 0.0,
627 count: 0,
628 }
629 }
630 pub fn push(&mut self, val: f64) {
632 let oldest = self.window[self.pos];
633 self.sum -= oldest;
634 self.sum += val;
635 self.window[self.pos] = val;
636 self.pos = (self.pos + 1) % self.capacity;
637 if self.count < self.capacity {
638 self.count += 1;
639 }
640 }
641 pub fn sum(&self) -> f64 {
643 self.sum
644 }
645 pub fn mean(&self) -> Option<f64> {
647 if self.count == 0 {
648 None
649 } else {
650 Some(self.sum / self.count as f64)
651 }
652 }
653 pub fn count(&self) -> usize {
655 self.count
656 }
657}
658#[allow(dead_code)]
660pub struct WriteOnce<T> {
661 value: std::cell::Cell<Option<T>>,
662}
663#[allow(dead_code)]
664impl<T: Copy> WriteOnce<T> {
665 pub fn new() -> Self {
667 Self {
668 value: std::cell::Cell::new(None),
669 }
670 }
671 pub fn write(&self, val: T) -> bool {
673 if self.value.get().is_some() {
674 return false;
675 }
676 self.value.set(Some(val));
677 true
678 }
679 pub fn read(&self) -> Option<T> {
681 self.value.get()
682 }
683 pub fn is_written(&self) -> bool {
685 self.value.get().is_some()
686 }
687}
688#[allow(dead_code)]
690pub struct StackCalc {
691 stack: Vec<i64>,
692}
693#[allow(dead_code)]
694impl StackCalc {
695 pub fn new() -> Self {
697 Self { stack: Vec::new() }
698 }
699 pub fn push(&mut self, n: i64) {
701 self.stack.push(n);
702 }
703 fn apply_binary(&mut self, op: impl FnOnce(i64, i64) -> i64) -> Option<i64> {
707 let (rest_len, a, b) = match self.stack[..] {
708 [ref rest @ .., a, b] => (rest.len(), a, b),
709 _ => return None,
710 };
711 let value = op(a, b);
712 self.stack.truncate(rest_len);
713 self.stack.push(value);
714 Some(value)
715 }
716 pub fn add(&mut self) -> Option<i64> {
720 self.apply_binary(|a, b| a + b)
721 }
722 pub fn sub(&mut self) -> Option<i64> {
726 self.apply_binary(|a, b| a - b)
727 }
728 pub fn mul(&mut self) -> Option<i64> {
732 self.apply_binary(|a, b| a * b)
733 }
734 pub fn peek(&self) -> Option<i64> {
736 self.stack.last().copied()
737 }
738 pub fn depth(&self) -> usize {
740 self.stack.len()
741 }
742}
743#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
745pub enum ErrorCategory {
746 Binding,
748 Universe,
750 TypeCheck,
752 Inductive,
754 Resolution,
756 Other,
758}
759#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
761pub enum KernelPhase {
762 Parse,
764 Elab,
766 TypeCheck,
768 Reduction,
770}
771#[allow(dead_code)]
773pub struct RewriteRuleSet {
774 rules: Vec<RewriteRule>,
775}
776#[allow(dead_code)]
777impl RewriteRuleSet {
778 pub fn new() -> Self {
780 Self { rules: Vec::new() }
781 }
782 pub fn add(&mut self, rule: RewriteRule) {
784 self.rules.push(rule);
785 }
786 pub fn len(&self) -> usize {
788 self.rules.len()
789 }
790 pub fn is_empty(&self) -> bool {
792 self.rules.is_empty()
793 }
794 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
796 self.rules.iter().filter(|r| r.conditional).collect()
797 }
798 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
800 self.rules.iter().filter(|r| !r.conditional).collect()
801 }
802 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
804 self.rules.iter().find(|r| r.name == name)
805 }
806}
807#[allow(dead_code)]
809pub struct StringPool {
810 free: Vec<String>,
811}
812#[allow(dead_code)]
813impl StringPool {
814 pub fn new() -> Self {
816 Self { free: Vec::new() }
817 }
818 pub fn take(&mut self) -> String {
820 self.free.pop().unwrap_or_default()
821 }
822 pub fn give(&mut self, mut s: String) {
824 s.clear();
825 self.free.push(s);
826 }
827 pub fn free_count(&self) -> usize {
829 self.free.len()
830 }
831}
832#[allow(dead_code)]
834pub struct PathBuf {
835 components: Vec<String>,
836}
837#[allow(dead_code)]
838impl PathBuf {
839 pub fn new() -> Self {
841 Self {
842 components: Vec::new(),
843 }
844 }
845 pub fn push(&mut self, comp: impl Into<String>) {
847 self.components.push(comp.into());
848 }
849 pub fn pop(&mut self) {
851 self.components.pop();
852 }
853 pub fn as_str(&self) -> String {
855 self.components.join("/")
856 }
857 pub fn depth(&self) -> usize {
859 self.components.len()
860 }
861 pub fn clear(&mut self) {
863 self.components.clear();
864 }
865}
866#[allow(dead_code)]
868pub struct TransitiveClosure {
869 adj: Vec<Vec<usize>>,
870 n: usize,
871}
872#[allow(dead_code)]
873impl TransitiveClosure {
874 pub fn new(n: usize) -> Self {
876 Self {
877 adj: vec![Vec::new(); n],
878 n,
879 }
880 }
881 pub fn add_edge(&mut self, from: usize, to: usize) {
883 if from < self.n {
884 self.adj[from].push(to);
885 }
886 }
887 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
889 let mut visited = vec![false; self.n];
890 let mut queue = std::collections::VecDeque::new();
891 queue.push_back(start);
892 while let Some(node) = queue.pop_front() {
893 if node >= self.n || visited[node] {
894 continue;
895 }
896 visited[node] = true;
897 for &next in &self.adj[node] {
898 queue.push_back(next);
899 }
900 }
901 (0..self.n).filter(|&i| visited[i]).collect()
902 }
903 pub fn can_reach(&self, from: usize, to: usize) -> bool {
905 self.reachable_from(from).contains(&to)
906 }
907}
908#[derive(Clone, Debug)]
910pub struct AnnotatedError {
911 pub error: KernelError,
913 pub notes: Vec<ErrorNote>,
915}
916impl AnnotatedError {
917 pub fn new(error: KernelError) -> Self {
919 Self {
920 error,
921 notes: Vec::new(),
922 }
923 }
924 pub fn with_note(mut self, note: ErrorNote) -> Self {
926 self.notes.push(note);
927 self
928 }
929 pub fn num_notes(&self) -> usize {
931 self.notes.len()
932 }
933 pub fn is_fatal(&self) -> bool {
935 self.error.is_fatal()
936 }
937}
938#[derive(Clone, Debug)]
940pub struct Diagnostic {
941 pub severity: Severity,
943 pub message: String,
945 pub location: Option<Name>,
947}
948impl Diagnostic {
949 pub fn error(message: impl Into<String>) -> Self {
951 Self {
952 severity: Severity::Error,
953 message: message.into(),
954 location: None,
955 }
956 }
957 pub fn warning(message: impl Into<String>) -> Self {
959 Self {
960 severity: Severity::Warning,
961 message: message.into(),
962 location: None,
963 }
964 }
965 pub fn info(message: impl Into<String>) -> Self {
967 Self {
968 severity: Severity::Info,
969 message: message.into(),
970 location: None,
971 }
972 }
973 pub fn at(mut self, loc: Name) -> Self {
975 self.location = Some(loc);
976 self
977 }
978 pub fn from_error(err: &KernelError) -> Self {
980 Self::error(err.to_string())
981 }
982}
983#[derive(Clone, Debug)]
985pub struct ErrorNote {
986 pub message: String,
988 pub location: Option<Name>,
990}
991impl ErrorNote {
992 pub fn new(message: impl Into<String>) -> Self {
994 Self {
995 message: message.into(),
996 location: None,
997 }
998 }
999 pub fn at(mut self, loc: Name) -> Self {
1001 self.location = Some(loc);
1002 self
1003 }
1004}
1005#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
1007pub enum Severity {
1008 Info,
1010 Warning,
1012 Error,
1014}
1015#[allow(dead_code)]
1017pub struct VersionedRecord<T: Clone> {
1018 earlier: Vec<T>,
1020 current: T,
1022}
1023#[allow(dead_code)]
1024impl<T: Clone> VersionedRecord<T> {
1025 pub fn new(initial: T) -> Self {
1027 Self {
1028 earlier: Vec::new(),
1029 current: initial,
1030 }
1031 }
1032 pub fn update(&mut self, val: T) {
1034 let previous = std::mem::replace(&mut self.current, val);
1035 self.earlier.push(previous);
1036 }
1037 pub fn current(&self) -> &T {
1039 &self.current
1040 }
1041 pub fn at_version(&self, n: usize) -> Option<&T> {
1043 match self.earlier.get(n) {
1044 Some(value) => Some(value),
1045 None if n == self.earlier.len() => Some(&self.current),
1046 None => None,
1047 }
1048 }
1049 pub fn version(&self) -> usize {
1051 self.earlier.len()
1052 }
1053 pub fn has_history(&self) -> bool {
1055 !self.earlier.is_empty()
1056 }
1057}
1058#[allow(dead_code)]
1060pub struct SimpleDag {
1061 edges: Vec<Vec<usize>>,
1063}
1064#[allow(dead_code)]
1065impl SimpleDag {
1066 pub fn new(n: usize) -> Self {
1068 Self {
1069 edges: vec![Vec::new(); n],
1070 }
1071 }
1072 pub fn add_edge(&mut self, from: usize, to: usize) {
1074 if from < self.edges.len() {
1075 self.edges[from].push(to);
1076 }
1077 }
1078 pub fn successors(&self, node: usize) -> &[usize] {
1080 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
1081 }
1082 pub fn can_reach(&self, from: usize, to: usize) -> bool {
1084 let mut visited = vec![false; self.edges.len()];
1085 self.dfs(from, to, &mut visited)
1086 }
1087 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
1088 if cur == target {
1089 return true;
1090 }
1091 if cur >= visited.len() || visited[cur] {
1092 return false;
1093 }
1094 visited[cur] = true;
1095 for &next in self.successors(cur) {
1096 if self.dfs(next, target, visited) {
1097 return true;
1098 }
1099 }
1100 false
1101 }
1102 pub fn topological_sort(&self) -> Option<Vec<usize>> {
1104 let n = self.edges.len();
1105 let mut in_degree = vec![0usize; n];
1106 for succs in &self.edges {
1107 for &s in succs {
1108 if s < n {
1109 in_degree[s] += 1;
1110 }
1111 }
1112 }
1113 let mut queue: std::collections::VecDeque<usize> =
1114 (0..n).filter(|&i| in_degree[i] == 0).collect();
1115 let mut order = Vec::new();
1116 while let Some(node) = queue.pop_front() {
1117 order.push(node);
1118 for &s in self.successors(node) {
1119 if s < n {
1120 in_degree[s] -= 1;
1121 if in_degree[s] == 0 {
1122 queue.push_back(s);
1123 }
1124 }
1125 }
1126 }
1127 if order.len() == n {
1128 Some(order)
1129 } else {
1130 None
1131 }
1132 }
1133 pub fn num_nodes(&self) -> usize {
1135 self.edges.len()
1136 }
1137}
1138#[allow(dead_code)]
1140pub enum Either2<A, B> {
1141 First(A),
1143 Second(B),
1145}
1146#[allow(dead_code)]
1147impl<A, B> Either2<A, B> {
1148 pub fn is_first(&self) -> bool {
1150 matches!(self, Either2::First(_))
1151 }
1152 pub fn is_second(&self) -> bool {
1154 matches!(self, Either2::Second(_))
1155 }
1156 pub fn first(self) -> Option<A> {
1158 match self {
1159 Either2::First(a) => Some(a),
1160 _ => None,
1161 }
1162 }
1163 pub fn second(self) -> Option<B> {
1165 match self {
1166 Either2::Second(b) => Some(b),
1167 _ => None,
1168 }
1169 }
1170 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
1172 match self {
1173 Either2::First(a) => Either2::First(f(a)),
1174 Either2::Second(b) => Either2::Second(b),
1175 }
1176 }
1177}
1178#[derive(Clone, Debug, Default)]
1180pub struct ErrorAccumulator {
1181 pub(super) errors: Vec<KernelError>,
1182}
1183impl ErrorAccumulator {
1184 pub fn new() -> Self {
1186 Self::default()
1187 }
1188 pub fn push(&mut self, err: KernelError) {
1190 self.errors.push(err);
1191 }
1192 pub fn is_empty(&self) -> bool {
1194 self.errors.is_empty()
1195 }
1196 pub fn len(&self) -> usize {
1198 self.errors.len()
1199 }
1200 pub fn iter(&self) -> impl Iterator<Item = &KernelError> {
1202 self.errors.iter()
1203 }
1204 pub fn drain(&mut self) -> Vec<KernelError> {
1206 std::mem::take(&mut self.errors)
1207 }
1208 #[allow(clippy::result_large_err)]
1210 pub fn into_result(mut self) -> Result<(), KernelError> {
1211 if self.errors.is_empty() {
1212 Ok(())
1213 } else {
1214 Err(self.errors.remove(0))
1215 }
1216 }
1217 pub fn count_by_category(&self) -> std::collections::HashMap<ErrorCategory, usize> {
1219 let mut counts = std::collections::HashMap::new();
1220 for err in &self.errors {
1221 *counts.entry(err.category()).or_insert(0) += 1;
1222 }
1223 counts
1224 }
1225 pub fn fatal_errors(&self) -> Vec<&KernelError> {
1227 self.errors.iter().filter(|e| e.is_fatal()).collect()
1228 }
1229 pub fn recoverable_errors(&self) -> Vec<&KernelError> {
1231 self.errors.iter().filter(|e| e.is_recoverable()).collect()
1232 }
1233}
1234#[derive(Clone, Debug)]
1236pub struct PhasedError {
1237 pub phase: KernelPhase,
1239 pub error: KernelError,
1241}
1242impl PhasedError {
1243 pub fn new(phase: KernelPhase, error: KernelError) -> Self {
1245 Self { phase, error }
1246 }
1247}
1248#[allow(dead_code)]
1250pub struct ConfigNode {
1251 key: String,
1252 value: Option<String>,
1253 children: Vec<ConfigNode>,
1254}
1255#[allow(dead_code)]
1256impl ConfigNode {
1257 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
1259 Self {
1260 key: key.into(),
1261 value: Some(value.into()),
1262 children: Vec::new(),
1263 }
1264 }
1265 pub fn section(key: impl Into<String>) -> Self {
1267 Self {
1268 key: key.into(),
1269 value: None,
1270 children: Vec::new(),
1271 }
1272 }
1273 pub fn add_child(&mut self, child: ConfigNode) {
1275 self.children.push(child);
1276 }
1277 pub fn key(&self) -> &str {
1279 &self.key
1280 }
1281 pub fn value(&self) -> Option<&str> {
1283 self.value.as_deref()
1284 }
1285 pub fn num_children(&self) -> usize {
1287 self.children.len()
1288 }
1289 pub fn lookup(&self, path: &str) -> Option<&str> {
1291 let mut parts = path.splitn(2, '.');
1292 let head = parts.next()?;
1293 let tail = parts.next();
1294 if head != self.key {
1295 return None;
1296 }
1297 match tail {
1298 None => self.value.as_deref(),
1299 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1300 }
1301 }
1302 fn lookup_relative(&self, path: &str) -> Option<&str> {
1303 let mut parts = path.splitn(2, '.');
1304 let head = parts.next()?;
1305 let tail = parts.next();
1306 if head != self.key {
1307 return None;
1308 }
1309 match tail {
1310 None => self.value.as_deref(),
1311 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1312 }
1313 }
1314}
1315#[allow(dead_code)]
1317pub struct TokenBucket {
1318 capacity: u64,
1319 tokens: u64,
1320 refill_per_ms: u64,
1321 last_refill: crate::wall_clock::Instant,
1322}
1323#[allow(dead_code)]
1324impl TokenBucket {
1325 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
1327 Self {
1328 capacity,
1329 tokens: capacity,
1330 refill_per_ms,
1331 last_refill: crate::wall_clock::Instant::now(),
1332 }
1333 }
1334 pub fn try_consume(&mut self, n: u64) -> bool {
1336 self.refill();
1337 if self.tokens >= n {
1338 self.tokens -= n;
1339 true
1340 } else {
1341 false
1342 }
1343 }
1344 fn refill(&mut self) {
1345 let now = crate::wall_clock::Instant::now();
1346 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
1347 if elapsed_ms > 0 {
1348 let new_tokens = elapsed_ms * self.refill_per_ms;
1349 self.tokens = (self.tokens + new_tokens).min(self.capacity);
1350 self.last_refill = now;
1351 }
1352 }
1353 pub fn available(&self) -> u64 {
1355 self.tokens
1356 }
1357 pub fn capacity(&self) -> u64 {
1359 self.capacity
1360 }
1361}
1362#[allow(dead_code)]
1364pub struct MinHeap<T: Ord> {
1365 data: Vec<T>,
1366}
1367#[allow(dead_code)]
1368impl<T: Ord> MinHeap<T> {
1369 pub fn new() -> Self {
1371 Self { data: Vec::new() }
1372 }
1373 pub fn push(&mut self, val: T) {
1375 self.data.push(val);
1376 self.sift_up(self.data.len() - 1);
1377 }
1378 pub fn pop(&mut self) -> Option<T> {
1380 if self.data.is_empty() {
1381 return None;
1382 }
1383 let n = self.data.len();
1384 self.data.swap(0, n - 1);
1385 let min = self.data.pop();
1386 if !self.data.is_empty() {
1387 self.sift_down(0);
1388 }
1389 min
1390 }
1391 pub fn peek(&self) -> Option<&T> {
1393 self.data.first()
1394 }
1395 pub fn len(&self) -> usize {
1397 self.data.len()
1398 }
1399 pub fn is_empty(&self) -> bool {
1401 self.data.is_empty()
1402 }
1403 fn sift_up(&mut self, mut i: usize) {
1404 while i > 0 {
1405 let parent = (i - 1) / 2;
1406 if self.data[i] < self.data[parent] {
1407 self.data.swap(i, parent);
1408 i = parent;
1409 } else {
1410 break;
1411 }
1412 }
1413 }
1414 fn sift_down(&mut self, mut i: usize) {
1415 let n = self.data.len();
1416 loop {
1417 let left = 2 * i + 1;
1418 let right = 2 * i + 2;
1419 let mut smallest = i;
1420 if left < n && self.data[left] < self.data[smallest] {
1421 smallest = left;
1422 }
1423 if right < n && self.data[right] < self.data[smallest] {
1424 smallest = right;
1425 }
1426 if smallest == i {
1427 break;
1428 }
1429 self.data.swap(i, smallest);
1430 i = smallest;
1431 }
1432 }
1433}
1434#[derive(Clone, Debug)]
1436pub struct ErrorReport {
1437 pub primary: KernelError,
1439 pub location: Option<Name>,
1441 pub notes: Vec<String>,
1443}
1444impl ErrorReport {
1445 pub fn new(primary: KernelError) -> Self {
1447 Self {
1448 primary,
1449 location: None,
1450 notes: vec![],
1451 }
1452 }
1453 pub fn with_location(mut self, loc: Name) -> Self {
1455 self.location = Some(loc);
1456 self
1457 }
1458 pub fn add_note(mut self, note: impl Into<String>) -> Self {
1460 self.notes.push(note.into());
1461 self
1462 }
1463 pub fn category(&self) -> ErrorCategory {
1465 self.primary.category()
1466 }
1467 pub fn is_recoverable(&self) -> bool {
1469 self.primary.is_recoverable()
1470 }
1471}
1472#[derive(Clone, Debug, Default)]
1474pub struct ErrorContext {
1475 frames: Vec<String>,
1476}
1477impl ErrorContext {
1478 pub fn new() -> Self {
1480 Self::default()
1481 }
1482 pub fn push(mut self, frame: impl Into<String>) -> Self {
1484 self.frames.push(frame.into());
1485 self
1486 }
1487 pub fn format(&self) -> String {
1489 self.frames
1490 .iter()
1491 .enumerate()
1492 .map(|(i, f)| format!(" #{} {}", i, f))
1493 .collect::<Vec<_>>()
1494 .join("\n")
1495 }
1496 pub fn into_error(self, msg: impl Into<String>) -> KernelError {
1498 if self.frames.is_empty() {
1499 KernelError::Other(msg.into())
1500 } else {
1501 KernelError::Other(format!("{}\nContext:\n{}", msg.into(), self.format()))
1502 }
1503 }
1504}
1505#[allow(dead_code)]
1507#[allow(missing_docs)]
1508pub enum DecisionNode {
1509 Leaf(String),
1511 Branch {
1513 key: String,
1514 val: String,
1515 yes_branch: Box<DecisionNode>,
1516 no_branch: Box<DecisionNode>,
1517 },
1518}
1519#[allow(dead_code)]
1520impl DecisionNode {
1521 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
1523 match self {
1524 DecisionNode::Leaf(action) => action.as_str(),
1525 DecisionNode::Branch {
1526 key,
1527 val,
1528 yes_branch,
1529 no_branch,
1530 } => {
1531 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
1532 if actual == val.as_str() {
1533 yes_branch.evaluate(ctx)
1534 } else {
1535 no_branch.evaluate(ctx)
1536 }
1537 }
1538 }
1539 }
1540 pub fn depth(&self) -> usize {
1542 match self {
1543 DecisionNode::Leaf(_) => 0,
1544 DecisionNode::Branch {
1545 yes_branch,
1546 no_branch,
1547 ..
1548 } => 1 + yes_branch.depth().max(no_branch.depth()),
1549 }
1550 }
1551}
1552#[allow(dead_code)]
1554pub struct PrefixCounter {
1555 children: std::collections::HashMap<char, PrefixCounter>,
1556 count: usize,
1557}
1558#[allow(dead_code)]
1559impl PrefixCounter {
1560 pub fn new() -> Self {
1562 Self {
1563 children: std::collections::HashMap::new(),
1564 count: 0,
1565 }
1566 }
1567 pub fn record(&mut self, s: &str) {
1569 self.count += 1;
1570 let mut node = self;
1571 for c in s.chars() {
1572 node = node.children.entry(c).or_default();
1573 node.count += 1;
1574 }
1575 }
1576 pub fn count_with_prefix(&self, prefix: &str) -> usize {
1578 let mut node = self;
1579 for c in prefix.chars() {
1580 match node.children.get(&c) {
1581 Some(n) => node = n,
1582 None => return 0,
1583 }
1584 }
1585 node.count
1586 }
1587}
1588#[allow(dead_code)]
1590pub struct WindowIterator<'a, T> {
1591 pub(super) data: &'a [T],
1592 pub(super) pos: usize,
1593 pub(super) window: usize,
1594}
1595#[allow(dead_code)]
1596impl<'a, T> WindowIterator<'a, T> {
1597 pub fn new(data: &'a [T], window: usize) -> Self {
1599 Self {
1600 data,
1601 pos: 0,
1602 window,
1603 }
1604 }
1605}
1606#[allow(dead_code)]
1608pub struct Fixture {
1609 data: std::collections::HashMap<String, String>,
1610}
1611#[allow(dead_code)]
1612impl Fixture {
1613 pub fn new() -> Self {
1615 Self {
1616 data: std::collections::HashMap::new(),
1617 }
1618 }
1619 pub fn set(&mut self, key: impl Into<String>, val: impl Into<String>) {
1621 self.data.insert(key.into(), val.into());
1622 }
1623 pub fn get(&self, key: &str) -> Option<&str> {
1625 self.data.get(key).map(|s| s.as_str())
1626 }
1627 pub fn len(&self) -> usize {
1629 self.data.len()
1630 }
1631 pub fn is_empty(&self) -> bool {
1633 self.len() == 0
1634 }
1635}