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),
284 Other(String),
286}
287impl KernelError {
288 pub fn category(&self) -> ErrorCategory {
290 match self {
291 KernelError::UnboundVariable(_) => ErrorCategory::Binding,
292 KernelError::UniverseInconsistency { .. } => ErrorCategory::Universe,
293 KernelError::TypeMismatch { .. }
294 | KernelError::NotASort(_)
295 | KernelError::NotAFunction(_) => ErrorCategory::TypeCheck,
296 KernelError::InvalidInductive(_)
297 | KernelError::InvalidRecursor(_)
298 | KernelError::InductiveError(_)
299 | KernelError::UnsupportedNestedInductive(_) => ErrorCategory::Inductive,
300 KernelError::UnknownConstant(_) => ErrorCategory::Resolution,
301 KernelError::Other(_) => ErrorCategory::Other,
302 }
303 }
304 pub fn is_recoverable(&self) -> bool {
306 matches!(
307 self,
308 KernelError::UnknownConstant(_) | KernelError::Other(_)
309 )
310 }
311 pub fn is_fatal(&self) -> bool {
313 !self.is_recoverable()
314 }
315 pub fn with_context(self, ctx: impl Into<String>) -> Self {
317 match self {
318 KernelError::TypeMismatch {
319 expected,
320 got,
321 context,
322 } => {
323 let new_ctx = format!("{} > {}", ctx.into(), context);
324 KernelError::TypeMismatch {
325 expected,
326 got,
327 context: new_ctx,
328 }
329 }
330 other => KernelError::Other(format!("{}: {}", ctx.into(), other)),
331 }
332 }
333 pub fn short_description(&self) -> String {
335 match self {
336 KernelError::TypeMismatch { context, .. } => {
337 format!("type mismatch in {}", context)
338 }
339 KernelError::UnboundVariable(idx) => format!("unbound variable #{}", idx),
340 KernelError::UnknownConstant(name) => format!("unknown constant '{}'", name),
341 KernelError::UniverseInconsistency { .. } => "universe inconsistency".to_string(),
342 KernelError::InvalidInductive(msg) => format!("invalid inductive: {}", msg),
343 KernelError::InvalidRecursor(msg) => format!("invalid recursor: {}", msg),
344 KernelError::NotASort(_) => "expected a sort".to_string(),
345 KernelError::NotAFunction(_) => "expected a function type".to_string(),
346 KernelError::InductiveError(msg) => format!("inductive error: {}", msg),
347 KernelError::UnsupportedNestedInductive(name) => {
348 format!("unsupported: nested inductive type '{}'", name)
349 }
350 KernelError::Other(msg) => msg.clone(),
351 }
352 }
353 pub fn type_mismatch(expected: Expr, got: Expr, context: impl Into<String>) -> Self {
355 KernelError::TypeMismatch {
356 expected,
357 got,
358 context: context.into(),
359 }
360 }
361 pub fn unknown(name: Name) -> Self {
363 KernelError::UnknownConstant(name)
364 }
365 pub fn universe(lhs: Level, rhs: Level) -> Self {
367 KernelError::UniverseInconsistency { lhs, rhs }
368 }
369}
370#[derive(Clone, Debug, Default)]
372pub struct DiagnosticCollection {
373 pub(super) diagnostics: Vec<Diagnostic>,
374}
375impl DiagnosticCollection {
376 pub fn new() -> Self {
378 Self::default()
379 }
380 pub fn add(&mut self, d: Diagnostic) {
382 self.diagnostics.push(d);
383 }
384 pub fn add_error(&mut self, err: &KernelError) {
386 self.add(Diagnostic::from_error(err));
387 }
388 pub fn has_errors(&self) -> bool {
390 self.diagnostics
391 .iter()
392 .any(|d| d.severity == Severity::Error)
393 }
394 pub fn is_empty(&self) -> bool {
396 self.diagnostics.is_empty()
397 }
398 pub fn len(&self) -> usize {
400 self.diagnostics.len()
401 }
402 pub fn iter(&self) -> impl Iterator<Item = &Diagnostic> {
404 self.diagnostics.iter()
405 }
406 pub fn by_severity(&self, severity: Severity) -> Vec<&Diagnostic> {
408 self.diagnostics
409 .iter()
410 .filter(|d| d.severity == severity)
411 .collect()
412 }
413 pub fn errors(&self) -> Vec<&Diagnostic> {
415 self.by_severity(Severity::Error)
416 }
417 pub fn warnings(&self) -> Vec<&Diagnostic> {
419 self.by_severity(Severity::Warning)
420 }
421}
422#[allow(dead_code)]
424pub struct NonEmptyVec<T> {
425 head: T,
426 tail: Vec<T>,
427}
428#[allow(dead_code)]
429impl<T> NonEmptyVec<T> {
430 pub fn singleton(val: T) -> Self {
432 Self {
433 head: val,
434 tail: Vec::new(),
435 }
436 }
437 pub fn push(&mut self, val: T) {
439 self.tail.push(val);
440 }
441 pub fn first(&self) -> &T {
443 &self.head
444 }
445 pub fn last(&self) -> &T {
447 self.tail.last().unwrap_or(&self.head)
448 }
449 pub fn len(&self) -> usize {
451 1 + self.tail.len()
452 }
453 pub fn is_empty(&self) -> bool {
455 self.len() == 0
456 }
457 pub fn to_vec(&self) -> Vec<&T> {
459 let mut v = vec![&self.head];
460 v.extend(self.tail.iter());
461 v
462 }
463}
464#[allow(dead_code)]
466pub struct FlatSubstitution {
467 pairs: Vec<(String, String)>,
468}
469#[allow(dead_code)]
470impl FlatSubstitution {
471 pub fn new() -> Self {
473 Self { pairs: Vec::new() }
474 }
475 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
477 self.pairs.push((from.into(), to.into()));
478 }
479 pub fn apply(&self, s: &str) -> String {
481 let mut result = s.to_string();
482 for (from, to) in &self.pairs {
483 result = result.replace(from.as_str(), to.as_str());
484 }
485 result
486 }
487 pub fn len(&self) -> usize {
489 self.pairs.len()
490 }
491 pub fn is_empty(&self) -> bool {
493 self.pairs.is_empty()
494 }
495}
496#[allow(dead_code)]
498pub struct LabelSet {
499 labels: Vec<String>,
500}
501#[allow(dead_code)]
502impl LabelSet {
503 pub fn new() -> Self {
505 Self { labels: Vec::new() }
506 }
507 pub fn add(&mut self, label: impl Into<String>) {
509 let s = label.into();
510 if !self.labels.contains(&s) {
511 self.labels.push(s);
512 }
513 }
514 pub fn has(&self, label: &str) -> bool {
516 self.labels.iter().any(|l| l == label)
517 }
518 pub fn count(&self) -> usize {
520 self.labels.len()
521 }
522 pub fn all(&self) -> &[String] {
524 &self.labels
525 }
526}
527#[allow(dead_code)]
529pub struct SparseVec<T: Default + Clone + PartialEq> {
530 entries: std::collections::HashMap<usize, T>,
531 default_: T,
532 logical_len: usize,
533}
534#[allow(dead_code)]
535impl<T: Default + Clone + PartialEq> SparseVec<T> {
536 pub fn new(len: usize) -> Self {
538 Self {
539 entries: std::collections::HashMap::new(),
540 default_: T::default(),
541 logical_len: len,
542 }
543 }
544 pub fn set(&mut self, idx: usize, val: T) {
546 if val == self.default_ {
547 self.entries.remove(&idx);
548 } else {
549 self.entries.insert(idx, val);
550 }
551 }
552 pub fn get(&self, idx: usize) -> &T {
554 self.entries.get(&idx).unwrap_or(&self.default_)
555 }
556 pub fn len(&self) -> usize {
558 self.logical_len
559 }
560 pub fn is_empty(&self) -> bool {
562 self.len() == 0
563 }
564 pub fn nnz(&self) -> usize {
566 self.entries.len()
567 }
568}
569#[allow(dead_code)]
571pub struct SmallMap<K: Ord + Clone, V: Clone> {
572 entries: Vec<(K, V)>,
573}
574#[allow(dead_code)]
575impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
576 pub fn new() -> Self {
578 Self {
579 entries: Vec::new(),
580 }
581 }
582 pub fn insert(&mut self, key: K, val: V) {
584 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
585 Ok(i) => self.entries[i].1 = val,
586 Err(i) => self.entries.insert(i, (key, val)),
587 }
588 }
589 pub fn get(&self, key: &K) -> Option<&V> {
591 self.entries
592 .binary_search_by_key(&key, |(k, _)| k)
593 .ok()
594 .map(|i| &self.entries[i].1)
595 }
596 pub fn len(&self) -> usize {
598 self.entries.len()
599 }
600 pub fn is_empty(&self) -> bool {
602 self.entries.is_empty()
603 }
604 pub fn keys(&self) -> Vec<&K> {
606 self.entries.iter().map(|(k, _)| k).collect()
607 }
608 pub fn values(&self) -> Vec<&V> {
610 self.entries.iter().map(|(_, v)| v).collect()
611 }
612}
613#[allow(dead_code)]
615pub struct SlidingSum {
616 window: Vec<f64>,
617 capacity: usize,
618 pos: usize,
619 sum: f64,
620 count: usize,
621}
622#[allow(dead_code)]
623impl SlidingSum {
624 pub fn new(capacity: usize) -> Self {
626 Self {
627 window: vec![0.0; capacity],
628 capacity,
629 pos: 0,
630 sum: 0.0,
631 count: 0,
632 }
633 }
634 pub fn push(&mut self, val: f64) {
636 let oldest = self.window[self.pos];
637 self.sum -= oldest;
638 self.sum += val;
639 self.window[self.pos] = val;
640 self.pos = (self.pos + 1) % self.capacity;
641 if self.count < self.capacity {
642 self.count += 1;
643 }
644 }
645 pub fn sum(&self) -> f64 {
647 self.sum
648 }
649 pub fn mean(&self) -> Option<f64> {
651 if self.count == 0 {
652 None
653 } else {
654 Some(self.sum / self.count as f64)
655 }
656 }
657 pub fn count(&self) -> usize {
659 self.count
660 }
661}
662#[allow(dead_code)]
664pub struct WriteOnce<T> {
665 value: std::cell::Cell<Option<T>>,
666}
667#[allow(dead_code)]
668impl<T: Copy> WriteOnce<T> {
669 pub fn new() -> Self {
671 Self {
672 value: std::cell::Cell::new(None),
673 }
674 }
675 pub fn write(&self, val: T) -> bool {
677 if self.value.get().is_some() {
678 return false;
679 }
680 self.value.set(Some(val));
681 true
682 }
683 pub fn read(&self) -> Option<T> {
685 self.value.get()
686 }
687 pub fn is_written(&self) -> bool {
689 self.value.get().is_some()
690 }
691}
692#[allow(dead_code)]
694pub struct StackCalc {
695 stack: Vec<i64>,
696}
697#[allow(dead_code)]
698impl StackCalc {
699 pub fn new() -> Self {
701 Self { stack: Vec::new() }
702 }
703 pub fn push(&mut self, n: i64) {
705 self.stack.push(n);
706 }
707 fn apply_binary(&mut self, op: impl FnOnce(i64, i64) -> i64) -> Option<i64> {
711 let (rest_len, a, b) = match self.stack[..] {
712 [ref rest @ .., a, b] => (rest.len(), a, b),
713 _ => return None,
714 };
715 let value = op(a, b);
716 self.stack.truncate(rest_len);
717 self.stack.push(value);
718 Some(value)
719 }
720 pub fn add(&mut self) -> Option<i64> {
724 self.apply_binary(|a, b| a + b)
725 }
726 pub fn sub(&mut self) -> Option<i64> {
730 self.apply_binary(|a, b| a - b)
731 }
732 pub fn mul(&mut self) -> Option<i64> {
736 self.apply_binary(|a, b| a * b)
737 }
738 pub fn peek(&self) -> Option<i64> {
740 self.stack.last().copied()
741 }
742 pub fn depth(&self) -> usize {
744 self.stack.len()
745 }
746}
747#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
749pub enum ErrorCategory {
750 Binding,
752 Universe,
754 TypeCheck,
756 Inductive,
758 Resolution,
760 Other,
762}
763#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
765pub enum KernelPhase {
766 Parse,
768 Elab,
770 TypeCheck,
772 Reduction,
774}
775#[allow(dead_code)]
777pub struct RewriteRuleSet {
778 rules: Vec<RewriteRule>,
779}
780#[allow(dead_code)]
781impl RewriteRuleSet {
782 pub fn new() -> Self {
784 Self { rules: Vec::new() }
785 }
786 pub fn add(&mut self, rule: RewriteRule) {
788 self.rules.push(rule);
789 }
790 pub fn len(&self) -> usize {
792 self.rules.len()
793 }
794 pub fn is_empty(&self) -> bool {
796 self.rules.is_empty()
797 }
798 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
800 self.rules.iter().filter(|r| r.conditional).collect()
801 }
802 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
804 self.rules.iter().filter(|r| !r.conditional).collect()
805 }
806 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
808 self.rules.iter().find(|r| r.name == name)
809 }
810}
811#[allow(dead_code)]
813pub struct StringPool {
814 free: Vec<String>,
815}
816#[allow(dead_code)]
817impl StringPool {
818 pub fn new() -> Self {
820 Self { free: Vec::new() }
821 }
822 pub fn take(&mut self) -> String {
824 self.free.pop().unwrap_or_default()
825 }
826 pub fn give(&mut self, mut s: String) {
828 s.clear();
829 self.free.push(s);
830 }
831 pub fn free_count(&self) -> usize {
833 self.free.len()
834 }
835}
836#[allow(dead_code)]
838pub struct PathBuf {
839 components: Vec<String>,
840}
841#[allow(dead_code)]
842impl PathBuf {
843 pub fn new() -> Self {
845 Self {
846 components: Vec::new(),
847 }
848 }
849 pub fn push(&mut self, comp: impl Into<String>) {
851 self.components.push(comp.into());
852 }
853 pub fn pop(&mut self) {
855 self.components.pop();
856 }
857 pub fn as_str(&self) -> String {
859 self.components.join("/")
860 }
861 pub fn depth(&self) -> usize {
863 self.components.len()
864 }
865 pub fn clear(&mut self) {
867 self.components.clear();
868 }
869}
870#[allow(dead_code)]
872pub struct TransitiveClosure {
873 adj: Vec<Vec<usize>>,
874 n: usize,
875}
876#[allow(dead_code)]
877impl TransitiveClosure {
878 pub fn new(n: usize) -> Self {
880 Self {
881 adj: vec![Vec::new(); n],
882 n,
883 }
884 }
885 pub fn add_edge(&mut self, from: usize, to: usize) {
887 if from < self.n {
888 self.adj[from].push(to);
889 }
890 }
891 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
893 let mut visited = vec![false; self.n];
894 let mut queue = std::collections::VecDeque::new();
895 queue.push_back(start);
896 while let Some(node) = queue.pop_front() {
897 if node >= self.n || visited[node] {
898 continue;
899 }
900 visited[node] = true;
901 for &next in &self.adj[node] {
902 queue.push_back(next);
903 }
904 }
905 (0..self.n).filter(|&i| visited[i]).collect()
906 }
907 pub fn can_reach(&self, from: usize, to: usize) -> bool {
909 self.reachable_from(from).contains(&to)
910 }
911}
912#[derive(Clone, Debug)]
914pub struct AnnotatedError {
915 pub error: KernelError,
917 pub notes: Vec<ErrorNote>,
919}
920impl AnnotatedError {
921 pub fn new(error: KernelError) -> Self {
923 Self {
924 error,
925 notes: Vec::new(),
926 }
927 }
928 pub fn with_note(mut self, note: ErrorNote) -> Self {
930 self.notes.push(note);
931 self
932 }
933 pub fn num_notes(&self) -> usize {
935 self.notes.len()
936 }
937 pub fn is_fatal(&self) -> bool {
939 self.error.is_fatal()
940 }
941}
942#[derive(Clone, Debug)]
944pub struct Diagnostic {
945 pub severity: Severity,
947 pub message: String,
949 pub location: Option<Name>,
951}
952impl Diagnostic {
953 pub fn error(message: impl Into<String>) -> Self {
955 Self {
956 severity: Severity::Error,
957 message: message.into(),
958 location: None,
959 }
960 }
961 pub fn warning(message: impl Into<String>) -> Self {
963 Self {
964 severity: Severity::Warning,
965 message: message.into(),
966 location: None,
967 }
968 }
969 pub fn info(message: impl Into<String>) -> Self {
971 Self {
972 severity: Severity::Info,
973 message: message.into(),
974 location: None,
975 }
976 }
977 pub fn at(mut self, loc: Name) -> Self {
979 self.location = Some(loc);
980 self
981 }
982 pub fn from_error(err: &KernelError) -> Self {
984 Self::error(err.to_string())
985 }
986}
987#[derive(Clone, Debug)]
989pub struct ErrorNote {
990 pub message: String,
992 pub location: Option<Name>,
994}
995impl ErrorNote {
996 pub fn new(message: impl Into<String>) -> Self {
998 Self {
999 message: message.into(),
1000 location: None,
1001 }
1002 }
1003 pub fn at(mut self, loc: Name) -> Self {
1005 self.location = Some(loc);
1006 self
1007 }
1008}
1009#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
1011pub enum Severity {
1012 Info,
1014 Warning,
1016 Error,
1018}
1019#[allow(dead_code)]
1021pub struct VersionedRecord<T: Clone> {
1022 earlier: Vec<T>,
1024 current: T,
1026}
1027#[allow(dead_code)]
1028impl<T: Clone> VersionedRecord<T> {
1029 pub fn new(initial: T) -> Self {
1031 Self {
1032 earlier: Vec::new(),
1033 current: initial,
1034 }
1035 }
1036 pub fn update(&mut self, val: T) {
1038 let previous = std::mem::replace(&mut self.current, val);
1039 self.earlier.push(previous);
1040 }
1041 pub fn current(&self) -> &T {
1043 &self.current
1044 }
1045 pub fn at_version(&self, n: usize) -> Option<&T> {
1047 match self.earlier.get(n) {
1048 Some(value) => Some(value),
1049 None if n == self.earlier.len() => Some(&self.current),
1050 None => None,
1051 }
1052 }
1053 pub fn version(&self) -> usize {
1055 self.earlier.len()
1056 }
1057 pub fn has_history(&self) -> bool {
1059 !self.earlier.is_empty()
1060 }
1061}
1062#[allow(dead_code)]
1064pub struct SimpleDag {
1065 edges: Vec<Vec<usize>>,
1067}
1068#[allow(dead_code)]
1069impl SimpleDag {
1070 pub fn new(n: usize) -> Self {
1072 Self {
1073 edges: vec![Vec::new(); n],
1074 }
1075 }
1076 pub fn add_edge(&mut self, from: usize, to: usize) {
1078 if from < self.edges.len() {
1079 self.edges[from].push(to);
1080 }
1081 }
1082 pub fn successors(&self, node: usize) -> &[usize] {
1084 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
1085 }
1086 pub fn can_reach(&self, from: usize, to: usize) -> bool {
1088 let mut visited = vec![false; self.edges.len()];
1089 self.dfs(from, to, &mut visited)
1090 }
1091 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
1092 if cur == target {
1093 return true;
1094 }
1095 if cur >= visited.len() || visited[cur] {
1096 return false;
1097 }
1098 visited[cur] = true;
1099 for &next in self.successors(cur) {
1100 if self.dfs(next, target, visited) {
1101 return true;
1102 }
1103 }
1104 false
1105 }
1106 pub fn topological_sort(&self) -> Option<Vec<usize>> {
1108 let n = self.edges.len();
1109 let mut in_degree = vec![0usize; n];
1110 for succs in &self.edges {
1111 for &s in succs {
1112 if s < n {
1113 in_degree[s] += 1;
1114 }
1115 }
1116 }
1117 let mut queue: std::collections::VecDeque<usize> =
1118 (0..n).filter(|&i| in_degree[i] == 0).collect();
1119 let mut order = Vec::new();
1120 while let Some(node) = queue.pop_front() {
1121 order.push(node);
1122 for &s in self.successors(node) {
1123 if s < n {
1124 in_degree[s] -= 1;
1125 if in_degree[s] == 0 {
1126 queue.push_back(s);
1127 }
1128 }
1129 }
1130 }
1131 if order.len() == n {
1132 Some(order)
1133 } else {
1134 None
1135 }
1136 }
1137 pub fn num_nodes(&self) -> usize {
1139 self.edges.len()
1140 }
1141}
1142#[allow(dead_code)]
1144pub enum Either2<A, B> {
1145 First(A),
1147 Second(B),
1149}
1150#[allow(dead_code)]
1151impl<A, B> Either2<A, B> {
1152 pub fn is_first(&self) -> bool {
1154 matches!(self, Either2::First(_))
1155 }
1156 pub fn is_second(&self) -> bool {
1158 matches!(self, Either2::Second(_))
1159 }
1160 pub fn first(self) -> Option<A> {
1162 match self {
1163 Either2::First(a) => Some(a),
1164 _ => None,
1165 }
1166 }
1167 pub fn second(self) -> Option<B> {
1169 match self {
1170 Either2::Second(b) => Some(b),
1171 _ => None,
1172 }
1173 }
1174 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
1176 match self {
1177 Either2::First(a) => Either2::First(f(a)),
1178 Either2::Second(b) => Either2::Second(b),
1179 }
1180 }
1181}
1182#[derive(Clone, Debug, Default)]
1184pub struct ErrorAccumulator {
1185 pub(super) errors: Vec<KernelError>,
1186}
1187impl ErrorAccumulator {
1188 pub fn new() -> Self {
1190 Self::default()
1191 }
1192 pub fn push(&mut self, err: KernelError) {
1194 self.errors.push(err);
1195 }
1196 pub fn is_empty(&self) -> bool {
1198 self.errors.is_empty()
1199 }
1200 pub fn len(&self) -> usize {
1202 self.errors.len()
1203 }
1204 pub fn iter(&self) -> impl Iterator<Item = &KernelError> {
1206 self.errors.iter()
1207 }
1208 pub fn drain(&mut self) -> Vec<KernelError> {
1210 std::mem::take(&mut self.errors)
1211 }
1212 #[allow(clippy::result_large_err)]
1214 pub fn into_result(mut self) -> Result<(), KernelError> {
1215 if self.errors.is_empty() {
1216 Ok(())
1217 } else {
1218 Err(self.errors.remove(0))
1219 }
1220 }
1221 pub fn count_by_category(&self) -> std::collections::HashMap<ErrorCategory, usize> {
1223 let mut counts = std::collections::HashMap::new();
1224 for err in &self.errors {
1225 *counts.entry(err.category()).or_insert(0) += 1;
1226 }
1227 counts
1228 }
1229 pub fn fatal_errors(&self) -> Vec<&KernelError> {
1231 self.errors.iter().filter(|e| e.is_fatal()).collect()
1232 }
1233 pub fn recoverable_errors(&self) -> Vec<&KernelError> {
1235 self.errors.iter().filter(|e| e.is_recoverable()).collect()
1236 }
1237}
1238#[derive(Clone, Debug)]
1240pub struct PhasedError {
1241 pub phase: KernelPhase,
1243 pub error: KernelError,
1245}
1246impl PhasedError {
1247 pub fn new(phase: KernelPhase, error: KernelError) -> Self {
1249 Self { phase, error }
1250 }
1251}
1252#[allow(dead_code)]
1254pub struct ConfigNode {
1255 key: String,
1256 value: Option<String>,
1257 children: Vec<ConfigNode>,
1258}
1259#[allow(dead_code)]
1260impl ConfigNode {
1261 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
1263 Self {
1264 key: key.into(),
1265 value: Some(value.into()),
1266 children: Vec::new(),
1267 }
1268 }
1269 pub fn section(key: impl Into<String>) -> Self {
1271 Self {
1272 key: key.into(),
1273 value: None,
1274 children: Vec::new(),
1275 }
1276 }
1277 pub fn add_child(&mut self, child: ConfigNode) {
1279 self.children.push(child);
1280 }
1281 pub fn key(&self) -> &str {
1283 &self.key
1284 }
1285 pub fn value(&self) -> Option<&str> {
1287 self.value.as_deref()
1288 }
1289 pub fn num_children(&self) -> usize {
1291 self.children.len()
1292 }
1293 pub fn lookup(&self, path: &str) -> Option<&str> {
1295 let mut parts = path.splitn(2, '.');
1296 let head = parts.next()?;
1297 let tail = parts.next();
1298 if head != self.key {
1299 return None;
1300 }
1301 match tail {
1302 None => self.value.as_deref(),
1303 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1304 }
1305 }
1306 fn lookup_relative(&self, path: &str) -> Option<&str> {
1307 let mut parts = path.splitn(2, '.');
1308 let head = parts.next()?;
1309 let tail = parts.next();
1310 if head != self.key {
1311 return None;
1312 }
1313 match tail {
1314 None => self.value.as_deref(),
1315 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1316 }
1317 }
1318}
1319#[allow(dead_code)]
1321pub struct TokenBucket {
1322 capacity: u64,
1323 tokens: u64,
1324 refill_per_ms: u64,
1325 last_refill: crate::wall_clock::Instant,
1326}
1327#[allow(dead_code)]
1328impl TokenBucket {
1329 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
1331 Self {
1332 capacity,
1333 tokens: capacity,
1334 refill_per_ms,
1335 last_refill: crate::wall_clock::Instant::now(),
1336 }
1337 }
1338 pub fn try_consume(&mut self, n: u64) -> bool {
1340 self.refill();
1341 if self.tokens >= n {
1342 self.tokens -= n;
1343 true
1344 } else {
1345 false
1346 }
1347 }
1348 fn refill(&mut self) {
1349 let now = crate::wall_clock::Instant::now();
1350 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
1351 if elapsed_ms > 0 {
1352 let new_tokens = elapsed_ms * self.refill_per_ms;
1353 self.tokens = (self.tokens + new_tokens).min(self.capacity);
1354 self.last_refill = now;
1355 }
1356 }
1357 pub fn available(&self) -> u64 {
1359 self.tokens
1360 }
1361 pub fn capacity(&self) -> u64 {
1363 self.capacity
1364 }
1365}
1366#[allow(dead_code)]
1368pub struct MinHeap<T: Ord> {
1369 data: Vec<T>,
1370}
1371#[allow(dead_code)]
1372impl<T: Ord> MinHeap<T> {
1373 pub fn new() -> Self {
1375 Self { data: Vec::new() }
1376 }
1377 pub fn push(&mut self, val: T) {
1379 self.data.push(val);
1380 self.sift_up(self.data.len() - 1);
1381 }
1382 pub fn pop(&mut self) -> Option<T> {
1384 if self.data.is_empty() {
1385 return None;
1386 }
1387 let n = self.data.len();
1388 self.data.swap(0, n - 1);
1389 let min = self.data.pop();
1390 if !self.data.is_empty() {
1391 self.sift_down(0);
1392 }
1393 min
1394 }
1395 pub fn peek(&self) -> Option<&T> {
1397 self.data.first()
1398 }
1399 pub fn len(&self) -> usize {
1401 self.data.len()
1402 }
1403 pub fn is_empty(&self) -> bool {
1405 self.data.is_empty()
1406 }
1407 fn sift_up(&mut self, mut i: usize) {
1408 while i > 0 {
1409 let parent = (i - 1) / 2;
1410 if self.data[i] < self.data[parent] {
1411 self.data.swap(i, parent);
1412 i = parent;
1413 } else {
1414 break;
1415 }
1416 }
1417 }
1418 fn sift_down(&mut self, mut i: usize) {
1419 let n = self.data.len();
1420 loop {
1421 let left = 2 * i + 1;
1422 let right = 2 * i + 2;
1423 let mut smallest = i;
1424 if left < n && self.data[left] < self.data[smallest] {
1425 smallest = left;
1426 }
1427 if right < n && self.data[right] < self.data[smallest] {
1428 smallest = right;
1429 }
1430 if smallest == i {
1431 break;
1432 }
1433 self.data.swap(i, smallest);
1434 i = smallest;
1435 }
1436 }
1437}
1438#[derive(Clone, Debug)]
1440pub struct ErrorReport {
1441 pub primary: KernelError,
1443 pub location: Option<Name>,
1445 pub notes: Vec<String>,
1447}
1448impl ErrorReport {
1449 pub fn new(primary: KernelError) -> Self {
1451 Self {
1452 primary,
1453 location: None,
1454 notes: vec![],
1455 }
1456 }
1457 pub fn with_location(mut self, loc: Name) -> Self {
1459 self.location = Some(loc);
1460 self
1461 }
1462 pub fn add_note(mut self, note: impl Into<String>) -> Self {
1464 self.notes.push(note.into());
1465 self
1466 }
1467 pub fn category(&self) -> ErrorCategory {
1469 self.primary.category()
1470 }
1471 pub fn is_recoverable(&self) -> bool {
1473 self.primary.is_recoverable()
1474 }
1475}
1476#[derive(Clone, Debug, Default)]
1478pub struct ErrorContext {
1479 frames: Vec<String>,
1480}
1481impl ErrorContext {
1482 pub fn new() -> Self {
1484 Self::default()
1485 }
1486 pub fn push(mut self, frame: impl Into<String>) -> Self {
1488 self.frames.push(frame.into());
1489 self
1490 }
1491 pub fn format(&self) -> String {
1493 self.frames
1494 .iter()
1495 .enumerate()
1496 .map(|(i, f)| format!(" #{} {}", i, f))
1497 .collect::<Vec<_>>()
1498 .join("\n")
1499 }
1500 pub fn into_error(self, msg: impl Into<String>) -> KernelError {
1502 if self.frames.is_empty() {
1503 KernelError::Other(msg.into())
1504 } else {
1505 KernelError::Other(format!("{}\nContext:\n{}", msg.into(), self.format()))
1506 }
1507 }
1508}
1509#[allow(dead_code)]
1511#[allow(missing_docs)]
1512pub enum DecisionNode {
1513 Leaf(String),
1515 Branch {
1517 key: String,
1518 val: String,
1519 yes_branch: Box<DecisionNode>,
1520 no_branch: Box<DecisionNode>,
1521 },
1522}
1523#[allow(dead_code)]
1524impl DecisionNode {
1525 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
1527 match self {
1528 DecisionNode::Leaf(action) => action.as_str(),
1529 DecisionNode::Branch {
1530 key,
1531 val,
1532 yes_branch,
1533 no_branch,
1534 } => {
1535 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
1536 if actual == val.as_str() {
1537 yes_branch.evaluate(ctx)
1538 } else {
1539 no_branch.evaluate(ctx)
1540 }
1541 }
1542 }
1543 }
1544 pub fn depth(&self) -> usize {
1546 match self {
1547 DecisionNode::Leaf(_) => 0,
1548 DecisionNode::Branch {
1549 yes_branch,
1550 no_branch,
1551 ..
1552 } => 1 + yes_branch.depth().max(no_branch.depth()),
1553 }
1554 }
1555}
1556#[allow(dead_code)]
1558pub struct PrefixCounter {
1559 children: std::collections::HashMap<char, PrefixCounter>,
1560 count: usize,
1561}
1562#[allow(dead_code)]
1563impl PrefixCounter {
1564 pub fn new() -> Self {
1566 Self {
1567 children: std::collections::HashMap::new(),
1568 count: 0,
1569 }
1570 }
1571 pub fn record(&mut self, s: &str) {
1573 self.count += 1;
1574 let mut node = self;
1575 for c in s.chars() {
1576 node = node.children.entry(c).or_default();
1577 node.count += 1;
1578 }
1579 }
1580 pub fn count_with_prefix(&self, prefix: &str) -> usize {
1582 let mut node = self;
1583 for c in prefix.chars() {
1584 match node.children.get(&c) {
1585 Some(n) => node = n,
1586 None => return 0,
1587 }
1588 }
1589 node.count
1590 }
1591}
1592#[allow(dead_code)]
1594pub struct WindowIterator<'a, T> {
1595 pub(super) data: &'a [T],
1596 pub(super) pos: usize,
1597 pub(super) window: usize,
1598}
1599#[allow(dead_code)]
1600impl<'a, T> WindowIterator<'a, T> {
1601 pub fn new(data: &'a [T], window: usize) -> Self {
1603 Self {
1604 data,
1605 pos: 0,
1606 window,
1607 }
1608 }
1609}
1610#[allow(dead_code)]
1612pub struct Fixture {
1613 data: std::collections::HashMap<String, String>,
1614}
1615#[allow(dead_code)]
1616impl Fixture {
1617 pub fn new() -> Self {
1619 Self {
1620 data: std::collections::HashMap::new(),
1621 }
1622 }
1623 pub fn set(&mut self, key: impl Into<String>, val: impl Into<String>) {
1625 self.data.insert(key.into(), val.into());
1626 }
1627 pub fn get(&self, key: &str) -> Option<&str> {
1629 self.data.get(key).map(|s| s.as_str())
1630 }
1631 pub fn len(&self) -> usize {
1633 self.data.len()
1634 }
1635 pub fn is_empty(&self) -> bool {
1637 self.len() == 0
1638 }
1639}