1use crate::{Expr, Level, Name};
6
7use std::collections::HashMap;
8
9#[allow(dead_code)]
11pub struct Stopwatch {
12 start: std::time::Instant,
13 splits: Vec<f64>,
14}
15#[allow(dead_code)]
16impl Stopwatch {
17 pub fn start() -> Self {
19 Self {
20 start: std::time::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 Other(String),
277}
278impl KernelError {
279 pub fn category(&self) -> ErrorCategory {
281 match self {
282 KernelError::UnboundVariable(_) => ErrorCategory::Binding,
283 KernelError::UniverseInconsistency { .. } => ErrorCategory::Universe,
284 KernelError::TypeMismatch { .. }
285 | KernelError::NotASort(_)
286 | KernelError::NotAFunction(_) => ErrorCategory::TypeCheck,
287 KernelError::InvalidInductive(_)
288 | KernelError::InvalidRecursor(_)
289 | KernelError::InductiveError(_) => ErrorCategory::Inductive,
290 KernelError::UnknownConstant(_) => ErrorCategory::Resolution,
291 KernelError::Other(_) => ErrorCategory::Other,
292 }
293 }
294 pub fn is_recoverable(&self) -> bool {
296 matches!(
297 self,
298 KernelError::UnknownConstant(_) | KernelError::Other(_)
299 )
300 }
301 pub fn is_fatal(&self) -> bool {
303 !self.is_recoverable()
304 }
305 pub fn with_context(self, ctx: impl Into<String>) -> Self {
307 match self {
308 KernelError::TypeMismatch {
309 expected,
310 got,
311 context,
312 } => {
313 let new_ctx = format!("{} > {}", ctx.into(), context);
314 KernelError::TypeMismatch {
315 expected,
316 got,
317 context: new_ctx,
318 }
319 }
320 other => KernelError::Other(format!("{}: {}", ctx.into(), other)),
321 }
322 }
323 pub fn short_description(&self) -> String {
325 match self {
326 KernelError::TypeMismatch { context, .. } => {
327 format!("type mismatch in {}", context)
328 }
329 KernelError::UnboundVariable(idx) => format!("unbound variable #{}", idx),
330 KernelError::UnknownConstant(name) => format!("unknown constant '{}'", name),
331 KernelError::UniverseInconsistency { .. } => "universe inconsistency".to_string(),
332 KernelError::InvalidInductive(msg) => format!("invalid inductive: {}", msg),
333 KernelError::InvalidRecursor(msg) => format!("invalid recursor: {}", msg),
334 KernelError::NotASort(_) => "expected a sort".to_string(),
335 KernelError::NotAFunction(_) => "expected a function type".to_string(),
336 KernelError::InductiveError(msg) => format!("inductive error: {}", msg),
337 KernelError::Other(msg) => msg.clone(),
338 }
339 }
340 pub fn type_mismatch(expected: Expr, got: Expr, context: impl Into<String>) -> Self {
342 KernelError::TypeMismatch {
343 expected,
344 got,
345 context: context.into(),
346 }
347 }
348 pub fn unknown(name: Name) -> Self {
350 KernelError::UnknownConstant(name)
351 }
352 pub fn universe(lhs: Level, rhs: Level) -> Self {
354 KernelError::UniverseInconsistency { lhs, rhs }
355 }
356}
357#[derive(Clone, Debug, Default)]
359pub struct DiagnosticCollection {
360 pub(super) diagnostics: Vec<Diagnostic>,
361}
362impl DiagnosticCollection {
363 pub fn new() -> Self {
365 Self::default()
366 }
367 pub fn add(&mut self, d: Diagnostic) {
369 self.diagnostics.push(d);
370 }
371 pub fn add_error(&mut self, err: &KernelError) {
373 self.add(Diagnostic::from_error(err));
374 }
375 pub fn has_errors(&self) -> bool {
377 self.diagnostics
378 .iter()
379 .any(|d| d.severity == Severity::Error)
380 }
381 pub fn is_empty(&self) -> bool {
383 self.diagnostics.is_empty()
384 }
385 pub fn len(&self) -> usize {
387 self.diagnostics.len()
388 }
389 pub fn iter(&self) -> impl Iterator<Item = &Diagnostic> {
391 self.diagnostics.iter()
392 }
393 pub fn by_severity(&self, severity: Severity) -> Vec<&Diagnostic> {
395 self.diagnostics
396 .iter()
397 .filter(|d| d.severity == severity)
398 .collect()
399 }
400 pub fn errors(&self) -> Vec<&Diagnostic> {
402 self.by_severity(Severity::Error)
403 }
404 pub fn warnings(&self) -> Vec<&Diagnostic> {
406 self.by_severity(Severity::Warning)
407 }
408}
409#[allow(dead_code)]
411pub struct NonEmptyVec<T> {
412 head: T,
413 tail: Vec<T>,
414}
415#[allow(dead_code)]
416impl<T> NonEmptyVec<T> {
417 pub fn singleton(val: T) -> Self {
419 Self {
420 head: val,
421 tail: Vec::new(),
422 }
423 }
424 pub fn push(&mut self, val: T) {
426 self.tail.push(val);
427 }
428 pub fn first(&self) -> &T {
430 &self.head
431 }
432 pub fn last(&self) -> &T {
434 self.tail.last().unwrap_or(&self.head)
435 }
436 pub fn len(&self) -> usize {
438 1 + self.tail.len()
439 }
440 pub fn is_empty(&self) -> bool {
442 self.len() == 0
443 }
444 pub fn to_vec(&self) -> Vec<&T> {
446 let mut v = vec![&self.head];
447 v.extend(self.tail.iter());
448 v
449 }
450}
451#[allow(dead_code)]
453pub struct FlatSubstitution {
454 pairs: Vec<(String, String)>,
455}
456#[allow(dead_code)]
457impl FlatSubstitution {
458 pub fn new() -> Self {
460 Self { pairs: Vec::new() }
461 }
462 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
464 self.pairs.push((from.into(), to.into()));
465 }
466 pub fn apply(&self, s: &str) -> String {
468 let mut result = s.to_string();
469 for (from, to) in &self.pairs {
470 result = result.replace(from.as_str(), to.as_str());
471 }
472 result
473 }
474 pub fn len(&self) -> usize {
476 self.pairs.len()
477 }
478 pub fn is_empty(&self) -> bool {
480 self.pairs.is_empty()
481 }
482}
483#[allow(dead_code)]
485pub struct LabelSet {
486 labels: Vec<String>,
487}
488#[allow(dead_code)]
489impl LabelSet {
490 pub fn new() -> Self {
492 Self { labels: Vec::new() }
493 }
494 pub fn add(&mut self, label: impl Into<String>) {
496 let s = label.into();
497 if !self.labels.contains(&s) {
498 self.labels.push(s);
499 }
500 }
501 pub fn has(&self, label: &str) -> bool {
503 self.labels.iter().any(|l| l == label)
504 }
505 pub fn count(&self) -> usize {
507 self.labels.len()
508 }
509 pub fn all(&self) -> &[String] {
511 &self.labels
512 }
513}
514#[allow(dead_code)]
516pub struct SparseVec<T: Default + Clone + PartialEq> {
517 entries: std::collections::HashMap<usize, T>,
518 default_: T,
519 logical_len: usize,
520}
521#[allow(dead_code)]
522impl<T: Default + Clone + PartialEq> SparseVec<T> {
523 pub fn new(len: usize) -> Self {
525 Self {
526 entries: std::collections::HashMap::new(),
527 default_: T::default(),
528 logical_len: len,
529 }
530 }
531 pub fn set(&mut self, idx: usize, val: T) {
533 if val == self.default_ {
534 self.entries.remove(&idx);
535 } else {
536 self.entries.insert(idx, val);
537 }
538 }
539 pub fn get(&self, idx: usize) -> &T {
541 self.entries.get(&idx).unwrap_or(&self.default_)
542 }
543 pub fn len(&self) -> usize {
545 self.logical_len
546 }
547 pub fn is_empty(&self) -> bool {
549 self.len() == 0
550 }
551 pub fn nnz(&self) -> usize {
553 self.entries.len()
554 }
555}
556#[allow(dead_code)]
558pub struct SmallMap<K: Ord + Clone, V: Clone> {
559 entries: Vec<(K, V)>,
560}
561#[allow(dead_code)]
562impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
563 pub fn new() -> Self {
565 Self {
566 entries: Vec::new(),
567 }
568 }
569 pub fn insert(&mut self, key: K, val: V) {
571 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
572 Ok(i) => self.entries[i].1 = val,
573 Err(i) => self.entries.insert(i, (key, val)),
574 }
575 }
576 pub fn get(&self, key: &K) -> Option<&V> {
578 self.entries
579 .binary_search_by_key(&key, |(k, _)| k)
580 .ok()
581 .map(|i| &self.entries[i].1)
582 }
583 pub fn len(&self) -> usize {
585 self.entries.len()
586 }
587 pub fn is_empty(&self) -> bool {
589 self.entries.is_empty()
590 }
591 pub fn keys(&self) -> Vec<&K> {
593 self.entries.iter().map(|(k, _)| k).collect()
594 }
595 pub fn values(&self) -> Vec<&V> {
597 self.entries.iter().map(|(_, v)| v).collect()
598 }
599}
600#[allow(dead_code)]
602pub struct SlidingSum {
603 window: Vec<f64>,
604 capacity: usize,
605 pos: usize,
606 sum: f64,
607 count: usize,
608}
609#[allow(dead_code)]
610impl SlidingSum {
611 pub fn new(capacity: usize) -> Self {
613 Self {
614 window: vec![0.0; capacity],
615 capacity,
616 pos: 0,
617 sum: 0.0,
618 count: 0,
619 }
620 }
621 pub fn push(&mut self, val: f64) {
623 let oldest = self.window[self.pos];
624 self.sum -= oldest;
625 self.sum += val;
626 self.window[self.pos] = val;
627 self.pos = (self.pos + 1) % self.capacity;
628 if self.count < self.capacity {
629 self.count += 1;
630 }
631 }
632 pub fn sum(&self) -> f64 {
634 self.sum
635 }
636 pub fn mean(&self) -> Option<f64> {
638 if self.count == 0 {
639 None
640 } else {
641 Some(self.sum / self.count as f64)
642 }
643 }
644 pub fn count(&self) -> usize {
646 self.count
647 }
648}
649#[allow(dead_code)]
651pub struct WriteOnce<T> {
652 value: std::cell::Cell<Option<T>>,
653}
654#[allow(dead_code)]
655impl<T: Copy> WriteOnce<T> {
656 pub fn new() -> Self {
658 Self {
659 value: std::cell::Cell::new(None),
660 }
661 }
662 pub fn write(&self, val: T) -> bool {
664 if self.value.get().is_some() {
665 return false;
666 }
667 self.value.set(Some(val));
668 true
669 }
670 pub fn read(&self) -> Option<T> {
672 self.value.get()
673 }
674 pub fn is_written(&self) -> bool {
676 self.value.get().is_some()
677 }
678}
679#[allow(dead_code)]
681pub struct StackCalc {
682 stack: Vec<i64>,
683}
684#[allow(dead_code)]
685impl StackCalc {
686 pub fn new() -> Self {
688 Self { stack: Vec::new() }
689 }
690 pub fn push(&mut self, n: i64) {
692 self.stack.push(n);
693 }
694 pub fn add(&mut self) {
696 let b = self
697 .stack
698 .pop()
699 .expect("stack must have at least two values for add");
700 let a = self
701 .stack
702 .pop()
703 .expect("stack must have at least two values for add");
704 self.stack.push(a + b);
705 }
706 pub fn sub(&mut self) {
708 let b = self
709 .stack
710 .pop()
711 .expect("stack must have at least two values for sub");
712 let a = self
713 .stack
714 .pop()
715 .expect("stack must have at least two values for sub");
716 self.stack.push(a - b);
717 }
718 pub fn mul(&mut self) {
720 let b = self
721 .stack
722 .pop()
723 .expect("stack must have at least two values for mul");
724 let a = self
725 .stack
726 .pop()
727 .expect("stack must have at least two values for mul");
728 self.stack.push(a * b);
729 }
730 pub fn peek(&self) -> Option<i64> {
732 self.stack.last().copied()
733 }
734 pub fn depth(&self) -> usize {
736 self.stack.len()
737 }
738}
739#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
741pub enum ErrorCategory {
742 Binding,
744 Universe,
746 TypeCheck,
748 Inductive,
750 Resolution,
752 Other,
754}
755#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
757pub enum KernelPhase {
758 Parse,
760 Elab,
762 TypeCheck,
764 Reduction,
766}
767#[allow(dead_code)]
769pub struct RewriteRuleSet {
770 rules: Vec<RewriteRule>,
771}
772#[allow(dead_code)]
773impl RewriteRuleSet {
774 pub fn new() -> Self {
776 Self { rules: Vec::new() }
777 }
778 pub fn add(&mut self, rule: RewriteRule) {
780 self.rules.push(rule);
781 }
782 pub fn len(&self) -> usize {
784 self.rules.len()
785 }
786 pub fn is_empty(&self) -> bool {
788 self.rules.is_empty()
789 }
790 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
792 self.rules.iter().filter(|r| r.conditional).collect()
793 }
794 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
796 self.rules.iter().filter(|r| !r.conditional).collect()
797 }
798 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
800 self.rules.iter().find(|r| r.name == name)
801 }
802}
803#[allow(dead_code)]
805pub struct StringPool {
806 free: Vec<String>,
807}
808#[allow(dead_code)]
809impl StringPool {
810 pub fn new() -> Self {
812 Self { free: Vec::new() }
813 }
814 pub fn take(&mut self) -> String {
816 self.free.pop().unwrap_or_default()
817 }
818 pub fn give(&mut self, mut s: String) {
820 s.clear();
821 self.free.push(s);
822 }
823 pub fn free_count(&self) -> usize {
825 self.free.len()
826 }
827}
828#[allow(dead_code)]
830pub struct PathBuf {
831 components: Vec<String>,
832}
833#[allow(dead_code)]
834impl PathBuf {
835 pub fn new() -> Self {
837 Self {
838 components: Vec::new(),
839 }
840 }
841 pub fn push(&mut self, comp: impl Into<String>) {
843 self.components.push(comp.into());
844 }
845 pub fn pop(&mut self) {
847 self.components.pop();
848 }
849 pub fn as_str(&self) -> String {
851 self.components.join("/")
852 }
853 pub fn depth(&self) -> usize {
855 self.components.len()
856 }
857 pub fn clear(&mut self) {
859 self.components.clear();
860 }
861}
862#[allow(dead_code)]
864pub struct TransitiveClosure {
865 adj: Vec<Vec<usize>>,
866 n: usize,
867}
868#[allow(dead_code)]
869impl TransitiveClosure {
870 pub fn new(n: usize) -> Self {
872 Self {
873 adj: vec![Vec::new(); n],
874 n,
875 }
876 }
877 pub fn add_edge(&mut self, from: usize, to: usize) {
879 if from < self.n {
880 self.adj[from].push(to);
881 }
882 }
883 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
885 let mut visited = vec![false; self.n];
886 let mut queue = std::collections::VecDeque::new();
887 queue.push_back(start);
888 while let Some(node) = queue.pop_front() {
889 if node >= self.n || visited[node] {
890 continue;
891 }
892 visited[node] = true;
893 for &next in &self.adj[node] {
894 queue.push_back(next);
895 }
896 }
897 (0..self.n).filter(|&i| visited[i]).collect()
898 }
899 pub fn can_reach(&self, from: usize, to: usize) -> bool {
901 self.reachable_from(from).contains(&to)
902 }
903}
904#[derive(Clone, Debug)]
906pub struct AnnotatedError {
907 pub error: KernelError,
909 pub notes: Vec<ErrorNote>,
911}
912impl AnnotatedError {
913 pub fn new(error: KernelError) -> Self {
915 Self {
916 error,
917 notes: Vec::new(),
918 }
919 }
920 pub fn with_note(mut self, note: ErrorNote) -> Self {
922 self.notes.push(note);
923 self
924 }
925 pub fn num_notes(&self) -> usize {
927 self.notes.len()
928 }
929 pub fn is_fatal(&self) -> bool {
931 self.error.is_fatal()
932 }
933}
934#[derive(Clone, Debug)]
936pub struct Diagnostic {
937 pub severity: Severity,
939 pub message: String,
941 pub location: Option<Name>,
943}
944impl Diagnostic {
945 pub fn error(message: impl Into<String>) -> Self {
947 Self {
948 severity: Severity::Error,
949 message: message.into(),
950 location: None,
951 }
952 }
953 pub fn warning(message: impl Into<String>) -> Self {
955 Self {
956 severity: Severity::Warning,
957 message: message.into(),
958 location: None,
959 }
960 }
961 pub fn info(message: impl Into<String>) -> Self {
963 Self {
964 severity: Severity::Info,
965 message: message.into(),
966 location: None,
967 }
968 }
969 pub fn at(mut self, loc: Name) -> Self {
971 self.location = Some(loc);
972 self
973 }
974 pub fn from_error(err: &KernelError) -> Self {
976 Self::error(err.to_string())
977 }
978}
979#[derive(Clone, Debug)]
981pub struct ErrorNote {
982 pub message: String,
984 pub location: Option<Name>,
986}
987impl ErrorNote {
988 pub fn new(message: impl Into<String>) -> Self {
990 Self {
991 message: message.into(),
992 location: None,
993 }
994 }
995 pub fn at(mut self, loc: Name) -> Self {
997 self.location = Some(loc);
998 self
999 }
1000}
1001#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
1003pub enum Severity {
1004 Info,
1006 Warning,
1008 Error,
1010}
1011#[allow(dead_code)]
1013pub struct VersionedRecord<T: Clone> {
1014 history: Vec<T>,
1015}
1016#[allow(dead_code)]
1017impl<T: Clone> VersionedRecord<T> {
1018 pub fn new(initial: T) -> Self {
1020 Self {
1021 history: vec![initial],
1022 }
1023 }
1024 pub fn update(&mut self, val: T) {
1026 self.history.push(val);
1027 }
1028 pub fn current(&self) -> &T {
1030 self.history
1031 .last()
1032 .expect("VersionedRecord history is always non-empty after construction")
1033 }
1034 pub fn at_version(&self, n: usize) -> Option<&T> {
1036 self.history.get(n)
1037 }
1038 pub fn version(&self) -> usize {
1040 self.history.len() - 1
1041 }
1042 pub fn has_history(&self) -> bool {
1044 self.history.len() > 1
1045 }
1046}
1047#[allow(dead_code)]
1049pub struct SimpleDag {
1050 edges: Vec<Vec<usize>>,
1052}
1053#[allow(dead_code)]
1054impl SimpleDag {
1055 pub fn new(n: usize) -> Self {
1057 Self {
1058 edges: vec![Vec::new(); n],
1059 }
1060 }
1061 pub fn add_edge(&mut self, from: usize, to: usize) {
1063 if from < self.edges.len() {
1064 self.edges[from].push(to);
1065 }
1066 }
1067 pub fn successors(&self, node: usize) -> &[usize] {
1069 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
1070 }
1071 pub fn can_reach(&self, from: usize, to: usize) -> bool {
1073 let mut visited = vec![false; self.edges.len()];
1074 self.dfs(from, to, &mut visited)
1075 }
1076 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
1077 if cur == target {
1078 return true;
1079 }
1080 if cur >= visited.len() || visited[cur] {
1081 return false;
1082 }
1083 visited[cur] = true;
1084 for &next in self.successors(cur) {
1085 if self.dfs(next, target, visited) {
1086 return true;
1087 }
1088 }
1089 false
1090 }
1091 pub fn topological_sort(&self) -> Option<Vec<usize>> {
1093 let n = self.edges.len();
1094 let mut in_degree = vec![0usize; n];
1095 for succs in &self.edges {
1096 for &s in succs {
1097 if s < n {
1098 in_degree[s] += 1;
1099 }
1100 }
1101 }
1102 let mut queue: std::collections::VecDeque<usize> =
1103 (0..n).filter(|&i| in_degree[i] == 0).collect();
1104 let mut order = Vec::new();
1105 while let Some(node) = queue.pop_front() {
1106 order.push(node);
1107 for &s in self.successors(node) {
1108 if s < n {
1109 in_degree[s] -= 1;
1110 if in_degree[s] == 0 {
1111 queue.push_back(s);
1112 }
1113 }
1114 }
1115 }
1116 if order.len() == n {
1117 Some(order)
1118 } else {
1119 None
1120 }
1121 }
1122 pub fn num_nodes(&self) -> usize {
1124 self.edges.len()
1125 }
1126}
1127#[allow(dead_code)]
1129pub enum Either2<A, B> {
1130 First(A),
1132 Second(B),
1134}
1135#[allow(dead_code)]
1136impl<A, B> Either2<A, B> {
1137 pub fn is_first(&self) -> bool {
1139 matches!(self, Either2::First(_))
1140 }
1141 pub fn is_second(&self) -> bool {
1143 matches!(self, Either2::Second(_))
1144 }
1145 pub fn first(self) -> Option<A> {
1147 match self {
1148 Either2::First(a) => Some(a),
1149 _ => None,
1150 }
1151 }
1152 pub fn second(self) -> Option<B> {
1154 match self {
1155 Either2::Second(b) => Some(b),
1156 _ => None,
1157 }
1158 }
1159 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
1161 match self {
1162 Either2::First(a) => Either2::First(f(a)),
1163 Either2::Second(b) => Either2::Second(b),
1164 }
1165 }
1166}
1167#[derive(Clone, Debug, Default)]
1169pub struct ErrorAccumulator {
1170 pub(super) errors: Vec<KernelError>,
1171}
1172impl ErrorAccumulator {
1173 pub fn new() -> Self {
1175 Self::default()
1176 }
1177 pub fn push(&mut self, err: KernelError) {
1179 self.errors.push(err);
1180 }
1181 pub fn is_empty(&self) -> bool {
1183 self.errors.is_empty()
1184 }
1185 pub fn len(&self) -> usize {
1187 self.errors.len()
1188 }
1189 pub fn iter(&self) -> impl Iterator<Item = &KernelError> {
1191 self.errors.iter()
1192 }
1193 pub fn drain(&mut self) -> Vec<KernelError> {
1195 std::mem::take(&mut self.errors)
1196 }
1197 #[allow(clippy::result_large_err)]
1199 pub fn into_result(mut self) -> Result<(), KernelError> {
1200 if self.errors.is_empty() {
1201 Ok(())
1202 } else {
1203 Err(self.errors.remove(0))
1204 }
1205 }
1206 pub fn count_by_category(&self) -> std::collections::HashMap<ErrorCategory, usize> {
1208 let mut counts = std::collections::HashMap::new();
1209 for err in &self.errors {
1210 *counts.entry(err.category()).or_insert(0) += 1;
1211 }
1212 counts
1213 }
1214 pub fn fatal_errors(&self) -> Vec<&KernelError> {
1216 self.errors.iter().filter(|e| e.is_fatal()).collect()
1217 }
1218 pub fn recoverable_errors(&self) -> Vec<&KernelError> {
1220 self.errors.iter().filter(|e| e.is_recoverable()).collect()
1221 }
1222}
1223#[derive(Clone, Debug)]
1225pub struct PhasedError {
1226 pub phase: KernelPhase,
1228 pub error: KernelError,
1230}
1231impl PhasedError {
1232 pub fn new(phase: KernelPhase, error: KernelError) -> Self {
1234 Self { phase, error }
1235 }
1236}
1237#[allow(dead_code)]
1239pub struct ConfigNode {
1240 key: String,
1241 value: Option<String>,
1242 children: Vec<ConfigNode>,
1243}
1244#[allow(dead_code)]
1245impl ConfigNode {
1246 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
1248 Self {
1249 key: key.into(),
1250 value: Some(value.into()),
1251 children: Vec::new(),
1252 }
1253 }
1254 pub fn section(key: impl Into<String>) -> Self {
1256 Self {
1257 key: key.into(),
1258 value: None,
1259 children: Vec::new(),
1260 }
1261 }
1262 pub fn add_child(&mut self, child: ConfigNode) {
1264 self.children.push(child);
1265 }
1266 pub fn key(&self) -> &str {
1268 &self.key
1269 }
1270 pub fn value(&self) -> Option<&str> {
1272 self.value.as_deref()
1273 }
1274 pub fn num_children(&self) -> usize {
1276 self.children.len()
1277 }
1278 pub fn lookup(&self, path: &str) -> Option<&str> {
1280 let mut parts = path.splitn(2, '.');
1281 let head = parts.next()?;
1282 let tail = parts.next();
1283 if head != self.key {
1284 return None;
1285 }
1286 match tail {
1287 None => self.value.as_deref(),
1288 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1289 }
1290 }
1291 fn lookup_relative(&self, path: &str) -> Option<&str> {
1292 let mut parts = path.splitn(2, '.');
1293 let head = parts.next()?;
1294 let tail = parts.next();
1295 if head != self.key {
1296 return None;
1297 }
1298 match tail {
1299 None => self.value.as_deref(),
1300 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1301 }
1302 }
1303}
1304#[allow(dead_code)]
1306pub struct TokenBucket {
1307 capacity: u64,
1308 tokens: u64,
1309 refill_per_ms: u64,
1310 last_refill: std::time::Instant,
1311}
1312#[allow(dead_code)]
1313impl TokenBucket {
1314 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
1316 Self {
1317 capacity,
1318 tokens: capacity,
1319 refill_per_ms,
1320 last_refill: std::time::Instant::now(),
1321 }
1322 }
1323 pub fn try_consume(&mut self, n: u64) -> bool {
1325 self.refill();
1326 if self.tokens >= n {
1327 self.tokens -= n;
1328 true
1329 } else {
1330 false
1331 }
1332 }
1333 fn refill(&mut self) {
1334 let now = std::time::Instant::now();
1335 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
1336 if elapsed_ms > 0 {
1337 let new_tokens = elapsed_ms * self.refill_per_ms;
1338 self.tokens = (self.tokens + new_tokens).min(self.capacity);
1339 self.last_refill = now;
1340 }
1341 }
1342 pub fn available(&self) -> u64 {
1344 self.tokens
1345 }
1346 pub fn capacity(&self) -> u64 {
1348 self.capacity
1349 }
1350}
1351#[allow(dead_code)]
1353pub struct MinHeap<T: Ord> {
1354 data: Vec<T>,
1355}
1356#[allow(dead_code)]
1357impl<T: Ord> MinHeap<T> {
1358 pub fn new() -> Self {
1360 Self { data: Vec::new() }
1361 }
1362 pub fn push(&mut self, val: T) {
1364 self.data.push(val);
1365 self.sift_up(self.data.len() - 1);
1366 }
1367 pub fn pop(&mut self) -> Option<T> {
1369 if self.data.is_empty() {
1370 return None;
1371 }
1372 let n = self.data.len();
1373 self.data.swap(0, n - 1);
1374 let min = self.data.pop();
1375 if !self.data.is_empty() {
1376 self.sift_down(0);
1377 }
1378 min
1379 }
1380 pub fn peek(&self) -> Option<&T> {
1382 self.data.first()
1383 }
1384 pub fn len(&self) -> usize {
1386 self.data.len()
1387 }
1388 pub fn is_empty(&self) -> bool {
1390 self.data.is_empty()
1391 }
1392 fn sift_up(&mut self, mut i: usize) {
1393 while i > 0 {
1394 let parent = (i - 1) / 2;
1395 if self.data[i] < self.data[parent] {
1396 self.data.swap(i, parent);
1397 i = parent;
1398 } else {
1399 break;
1400 }
1401 }
1402 }
1403 fn sift_down(&mut self, mut i: usize) {
1404 let n = self.data.len();
1405 loop {
1406 let left = 2 * i + 1;
1407 let right = 2 * i + 2;
1408 let mut smallest = i;
1409 if left < n && self.data[left] < self.data[smallest] {
1410 smallest = left;
1411 }
1412 if right < n && self.data[right] < self.data[smallest] {
1413 smallest = right;
1414 }
1415 if smallest == i {
1416 break;
1417 }
1418 self.data.swap(i, smallest);
1419 i = smallest;
1420 }
1421 }
1422}
1423#[derive(Clone, Debug)]
1425pub struct ErrorReport {
1426 pub primary: KernelError,
1428 pub location: Option<Name>,
1430 pub notes: Vec<String>,
1432}
1433impl ErrorReport {
1434 pub fn new(primary: KernelError) -> Self {
1436 Self {
1437 primary,
1438 location: None,
1439 notes: vec![],
1440 }
1441 }
1442 pub fn with_location(mut self, loc: Name) -> Self {
1444 self.location = Some(loc);
1445 self
1446 }
1447 pub fn add_note(mut self, note: impl Into<String>) -> Self {
1449 self.notes.push(note.into());
1450 self
1451 }
1452 pub fn category(&self) -> ErrorCategory {
1454 self.primary.category()
1455 }
1456 pub fn is_recoverable(&self) -> bool {
1458 self.primary.is_recoverable()
1459 }
1460}
1461#[derive(Clone, Debug, Default)]
1463pub struct ErrorContext {
1464 frames: Vec<String>,
1465}
1466impl ErrorContext {
1467 pub fn new() -> Self {
1469 Self::default()
1470 }
1471 pub fn push(mut self, frame: impl Into<String>) -> Self {
1473 self.frames.push(frame.into());
1474 self
1475 }
1476 pub fn format(&self) -> String {
1478 self.frames
1479 .iter()
1480 .enumerate()
1481 .map(|(i, f)| format!(" #{} {}", i, f))
1482 .collect::<Vec<_>>()
1483 .join("\n")
1484 }
1485 pub fn into_error(self, msg: impl Into<String>) -> KernelError {
1487 if self.frames.is_empty() {
1488 KernelError::Other(msg.into())
1489 } else {
1490 KernelError::Other(format!("{}\nContext:\n{}", msg.into(), self.format()))
1491 }
1492 }
1493}
1494#[allow(dead_code)]
1496#[allow(missing_docs)]
1497pub enum DecisionNode {
1498 Leaf(String),
1500 Branch {
1502 key: String,
1503 val: String,
1504 yes_branch: Box<DecisionNode>,
1505 no_branch: Box<DecisionNode>,
1506 },
1507}
1508#[allow(dead_code)]
1509impl DecisionNode {
1510 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
1512 match self {
1513 DecisionNode::Leaf(action) => action.as_str(),
1514 DecisionNode::Branch {
1515 key,
1516 val,
1517 yes_branch,
1518 no_branch,
1519 } => {
1520 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
1521 if actual == val.as_str() {
1522 yes_branch.evaluate(ctx)
1523 } else {
1524 no_branch.evaluate(ctx)
1525 }
1526 }
1527 }
1528 }
1529 pub fn depth(&self) -> usize {
1531 match self {
1532 DecisionNode::Leaf(_) => 0,
1533 DecisionNode::Branch {
1534 yes_branch,
1535 no_branch,
1536 ..
1537 } => 1 + yes_branch.depth().max(no_branch.depth()),
1538 }
1539 }
1540}
1541#[allow(dead_code)]
1543pub struct PrefixCounter {
1544 children: std::collections::HashMap<char, PrefixCounter>,
1545 count: usize,
1546}
1547#[allow(dead_code)]
1548impl PrefixCounter {
1549 pub fn new() -> Self {
1551 Self {
1552 children: std::collections::HashMap::new(),
1553 count: 0,
1554 }
1555 }
1556 pub fn record(&mut self, s: &str) {
1558 self.count += 1;
1559 let mut node = self;
1560 for c in s.chars() {
1561 node = node.children.entry(c).or_default();
1562 node.count += 1;
1563 }
1564 }
1565 pub fn count_with_prefix(&self, prefix: &str) -> usize {
1567 let mut node = self;
1568 for c in prefix.chars() {
1569 match node.children.get(&c) {
1570 Some(n) => node = n,
1571 None => return 0,
1572 }
1573 }
1574 node.count
1575 }
1576}
1577#[allow(dead_code)]
1579pub struct WindowIterator<'a, T> {
1580 pub(super) data: &'a [T],
1581 pub(super) pos: usize,
1582 pub(super) window: usize,
1583}
1584#[allow(dead_code)]
1585impl<'a, T> WindowIterator<'a, T> {
1586 pub fn new(data: &'a [T], window: usize) -> Self {
1588 Self {
1589 data,
1590 pos: 0,
1591 window,
1592 }
1593 }
1594}
1595#[allow(dead_code)]
1597pub struct Fixture {
1598 data: std::collections::HashMap<String, String>,
1599}
1600#[allow(dead_code)]
1601impl Fixture {
1602 pub fn new() -> Self {
1604 Self {
1605 data: std::collections::HashMap::new(),
1606 }
1607 }
1608 pub fn set(&mut self, key: impl Into<String>, val: impl Into<String>) {
1610 self.data.insert(key.into(), val.into());
1611 }
1612 pub fn get(&self, key: &str) -> Option<&str> {
1614 self.data.get(key).map(|s| s.as_str())
1615 }
1616 pub fn len(&self) -> usize {
1618 self.data.len()
1619 }
1620 pub fn is_empty(&self) -> bool {
1622 self.len() == 0
1623 }
1624}