1use crate::{Expr, Name};
6use std::collections::HashMap;
7
8#[allow(dead_code)]
10pub struct WindowIterator<'a, T> {
11 pub(super) data: &'a [T],
12 pub(super) pos: usize,
13 pub(super) window: usize,
14}
15#[allow(dead_code)]
16impl<'a, T> WindowIterator<'a, T> {
17 pub fn new(data: &'a [T], window: usize) -> Self {
19 Self {
20 data,
21 pos: 0,
22 window,
23 }
24 }
25}
26#[allow(dead_code)]
28pub struct MinHeap<T: Ord> {
29 data: Vec<T>,
30}
31#[allow(dead_code)]
32impl<T: Ord> MinHeap<T> {
33 pub fn new() -> Self {
35 Self { data: Vec::new() }
36 }
37 pub fn push(&mut self, val: T) {
39 self.data.push(val);
40 self.sift_up(self.data.len() - 1);
41 }
42 pub fn pop(&mut self) -> Option<T> {
44 if self.data.is_empty() {
45 return None;
46 }
47 let n = self.data.len();
48 self.data.swap(0, n - 1);
49 let min = self.data.pop();
50 if !self.data.is_empty() {
51 self.sift_down(0);
52 }
53 min
54 }
55 pub fn peek(&self) -> Option<&T> {
57 self.data.first()
58 }
59 pub fn len(&self) -> usize {
61 self.data.len()
62 }
63 pub fn is_empty(&self) -> bool {
65 self.data.is_empty()
66 }
67 fn sift_up(&mut self, mut i: usize) {
68 while i > 0 {
69 let parent = (i - 1) / 2;
70 if self.data[i] < self.data[parent] {
71 self.data.swap(i, parent);
72 i = parent;
73 } else {
74 break;
75 }
76 }
77 }
78 fn sift_down(&mut self, mut i: usize) {
79 let n = self.data.len();
80 loop {
81 let left = 2 * i + 1;
82 let right = 2 * i + 2;
83 let mut smallest = i;
84 if left < n && self.data[left] < self.data[smallest] {
85 smallest = left;
86 }
87 if right < n && self.data[right] < self.data[smallest] {
88 smallest = right;
89 }
90 if smallest == i {
91 break;
92 }
93 self.data.swap(i, smallest);
94 i = smallest;
95 }
96 }
97}
98#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
100pub enum FfiSafety {
101 Safe,
103 Unsafe,
105 System,
107}
108#[allow(dead_code)]
110pub struct Stopwatch {
111 start: crate::wall_clock::Instant,
112 splits: Vec<f64>,
113}
114#[allow(dead_code)]
115impl Stopwatch {
116 pub fn start() -> Self {
118 Self {
119 start: crate::wall_clock::Instant::now(),
120 splits: Vec::new(),
121 }
122 }
123 pub fn split(&mut self) {
125 self.splits.push(self.elapsed_ms());
126 }
127 pub fn elapsed_ms(&self) -> f64 {
129 self.start.elapsed().as_secs_f64() * 1000.0
130 }
131 pub fn splits(&self) -> &[f64] {
133 &self.splits
134 }
135 pub fn num_splits(&self) -> usize {
137 self.splits.len()
138 }
139}
140#[allow(dead_code)]
142pub struct ConfigNode {
143 key: String,
144 value: Option<String>,
145 children: Vec<ConfigNode>,
146}
147#[allow(dead_code)]
148impl ConfigNode {
149 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
151 Self {
152 key: key.into(),
153 value: Some(value.into()),
154 children: Vec::new(),
155 }
156 }
157 pub fn section(key: impl Into<String>) -> Self {
159 Self {
160 key: key.into(),
161 value: None,
162 children: Vec::new(),
163 }
164 }
165 pub fn add_child(&mut self, child: ConfigNode) {
167 self.children.push(child);
168 }
169 pub fn key(&self) -> &str {
171 &self.key
172 }
173 pub fn value(&self) -> Option<&str> {
175 self.value.as_deref()
176 }
177 pub fn num_children(&self) -> usize {
179 self.children.len()
180 }
181 pub fn lookup(&self, path: &str) -> Option<&str> {
183 let mut parts = path.splitn(2, '.');
184 let head = parts.next()?;
185 let tail = parts.next();
186 if head != self.key {
187 return None;
188 }
189 match tail {
190 None => self.value.as_deref(),
191 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
192 }
193 }
194 fn lookup_relative(&self, path: &str) -> Option<&str> {
195 let mut parts = path.splitn(2, '.');
196 let head = parts.next()?;
197 let tail = parts.next();
198 if head != self.key {
199 return None;
200 }
201 match tail {
202 None => self.value.as_deref(),
203 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
204 }
205 }
206}
207#[allow(dead_code)]
209pub struct SparseVec<T: Default + Clone + PartialEq> {
210 entries: std::collections::HashMap<usize, T>,
211 default_: T,
212 logical_len: usize,
213}
214#[allow(dead_code)]
215impl<T: Default + Clone + PartialEq> SparseVec<T> {
216 pub fn new(len: usize) -> Self {
218 Self {
219 entries: std::collections::HashMap::new(),
220 default_: T::default(),
221 logical_len: len,
222 }
223 }
224 pub fn set(&mut self, idx: usize, val: T) {
226 if val == self.default_ {
227 self.entries.remove(&idx);
228 } else {
229 self.entries.insert(idx, val);
230 }
231 }
232 pub fn get(&self, idx: usize) -> &T {
234 self.entries.get(&idx).unwrap_or(&self.default_)
235 }
236 pub fn len(&self) -> usize {
238 self.logical_len
239 }
240 pub fn is_empty(&self) -> bool {
242 self.len() == 0
243 }
244 pub fn nnz(&self) -> usize {
246 self.entries.len()
247 }
248}
249#[allow(dead_code)]
251pub struct Fixture {
252 data: std::collections::HashMap<String, String>,
253}
254#[allow(dead_code)]
255impl Fixture {
256 pub fn new() -> Self {
258 Self {
259 data: std::collections::HashMap::new(),
260 }
261 }
262 pub fn set(&mut self, key: impl Into<String>, val: impl Into<String>) {
264 self.data.insert(key.into(), val.into());
265 }
266 pub fn get(&self, key: &str) -> Option<&str> {
268 self.data.get(key).map(|s| s.as_str())
269 }
270 pub fn len(&self) -> usize {
272 self.data.len()
273 }
274 pub fn is_empty(&self) -> bool {
276 self.len() == 0
277 }
278}
279#[allow(dead_code)]
281pub struct WriteOnce<T> {
282 value: std::cell::Cell<Option<T>>,
283}
284#[allow(dead_code)]
285impl<T: Copy> WriteOnce<T> {
286 pub fn new() -> Self {
288 Self {
289 value: std::cell::Cell::new(None),
290 }
291 }
292 pub fn write(&self, val: T) -> bool {
294 if self.value.get().is_some() {
295 return false;
296 }
297 self.value.set(Some(val));
298 true
299 }
300 pub fn read(&self) -> Option<T> {
302 self.value.get()
303 }
304 pub fn is_written(&self) -> bool {
306 self.value.get().is_some()
307 }
308}
309#[allow(dead_code)]
311pub struct PathBuf {
312 components: Vec<String>,
313}
314#[allow(dead_code)]
315impl PathBuf {
316 pub fn new() -> Self {
318 Self {
319 components: Vec::new(),
320 }
321 }
322 pub fn push(&mut self, comp: impl Into<String>) {
324 self.components.push(comp.into());
325 }
326 pub fn pop(&mut self) {
328 self.components.pop();
329 }
330 pub fn as_str(&self) -> String {
332 self.components.join("/")
333 }
334 pub fn depth(&self) -> usize {
336 self.components.len()
337 }
338 pub fn clear(&mut self) {
340 self.components.clear();
341 }
342}
343#[allow(dead_code)]
345#[allow(missing_docs)]
346pub struct RewriteRule {
347 pub name: String,
349 pub lhs: String,
351 pub rhs: String,
353 pub conditional: bool,
355}
356#[allow(dead_code)]
357impl RewriteRule {
358 pub fn unconditional(
360 name: impl Into<String>,
361 lhs: impl Into<String>,
362 rhs: impl Into<String>,
363 ) -> Self {
364 Self {
365 name: name.into(),
366 lhs: lhs.into(),
367 rhs: rhs.into(),
368 conditional: false,
369 }
370 }
371 pub fn conditional(
373 name: impl Into<String>,
374 lhs: impl Into<String>,
375 rhs: impl Into<String>,
376 ) -> Self {
377 Self {
378 name: name.into(),
379 lhs: lhs.into(),
380 rhs: rhs.into(),
381 conditional: true,
382 }
383 }
384 pub fn display(&self) -> String {
386 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
387 }
388}
389#[allow(dead_code)]
391#[allow(missing_docs)]
392pub enum DecisionNode {
393 Leaf(String),
395 Branch {
397 key: String,
398 val: String,
399 yes_branch: Box<DecisionNode>,
400 no_branch: Box<DecisionNode>,
401 },
402}
403#[allow(dead_code)]
404impl DecisionNode {
405 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
407 match self {
408 DecisionNode::Leaf(action) => action.as_str(),
409 DecisionNode::Branch {
410 key,
411 val,
412 yes_branch,
413 no_branch,
414 } => {
415 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
416 if actual == val.as_str() {
417 yes_branch.evaluate(ctx)
418 } else {
419 no_branch.evaluate(ctx)
420 }
421 }
422 }
423 }
424 pub fn depth(&self) -> usize {
426 match self {
427 DecisionNode::Leaf(_) => 0,
428 DecisionNode::Branch {
429 yes_branch,
430 no_branch,
431 ..
432 } => 1 + yes_branch.depth().max(no_branch.depth()),
433 }
434 }
435}
436#[allow(dead_code)]
438pub struct SlidingSum {
439 window: Vec<f64>,
440 capacity: usize,
441 pos: usize,
442 sum: f64,
443 count: usize,
444}
445#[allow(dead_code)]
446impl SlidingSum {
447 pub fn new(capacity: usize) -> Self {
449 Self {
450 window: vec![0.0; capacity],
451 capacity,
452 pos: 0,
453 sum: 0.0,
454 count: 0,
455 }
456 }
457 pub fn push(&mut self, val: f64) {
459 let oldest = self.window[self.pos];
460 self.sum -= oldest;
461 self.sum += val;
462 self.window[self.pos] = val;
463 self.pos = (self.pos + 1) % self.capacity;
464 if self.count < self.capacity {
465 self.count += 1;
466 }
467 }
468 pub fn sum(&self) -> f64 {
470 self.sum
471 }
472 pub fn mean(&self) -> Option<f64> {
474 if self.count == 0 {
475 None
476 } else {
477 Some(self.sum / self.count as f64)
478 }
479 }
480 pub fn count(&self) -> usize {
482 self.count
483 }
484}
485#[derive(Clone, Debug, PartialEq)]
487pub enum FfiValue {
488 Bool(bool),
490 UInt(u64),
492 Int(i64),
494 Float(f64),
496 Str(String),
498 Bytes(Vec<u8>),
500 Unit,
502}
503impl FfiValue {
504 pub fn try_from_expr(expr: &Expr, ty: &FfiType) -> Result<Self, FfiError> {
506 match (expr, ty) {
507 (Expr::Lit(crate::Literal::Nat(n)), FfiType::UInt64) => match n.to_u64() {
508 Some(v) => Ok(FfiValue::UInt(v)),
509 None => Err(FfiError::ValueOutOfRange(format!(
510 "u64 range exceeded: {}",
511 n
512 ))),
513 },
514 (Expr::Lit(crate::Literal::Nat(n)), FfiType::UInt32) => {
515 match n.to_u64().filter(|v| *v <= u32::MAX as u64) {
516 Some(v) => Ok(FfiValue::UInt(v)),
517 None => Err(FfiError::ValueOutOfRange(format!(
518 "u32 range exceeded: {}",
519 n
520 ))),
521 }
522 }
523 (Expr::Lit(crate::Literal::Nat(n)), FfiType::Int64) => {
524 match n.to_u64().filter(|v| *v <= i64::MAX as u64) {
525 Some(v) => Ok(FfiValue::Int(v as i64)),
526 None => Err(FfiError::ValueOutOfRange(format!(
527 "i64 range exceeded: {}",
528 n
529 ))),
530 }
531 }
532 (Expr::Lit(crate::Literal::Str(s)), FfiType::String) => Ok(FfiValue::Str(s.clone())),
533 _ => Err(FfiError::TypeMismatch(format!(
534 "Cannot convert {:?} to {:?}",
535 expr, ty
536 ))),
537 }
538 }
539 pub fn to_expr(&self) -> Expr {
541 match self {
542 FfiValue::Bool(b) => Expr::Const(
543 if *b {
544 Name::str("True")
545 } else {
546 Name::str("False")
547 },
548 vec![],
549 ),
550 FfiValue::UInt(n) => Expr::Lit(crate::Literal::nat(*n)),
551 FfiValue::Int(n) => {
552 if *n >= 0 {
553 Expr::Lit(crate::Literal::nat(*n as u64))
554 } else {
555 Expr::Const(Name::str("Int.neg"), vec![])
556 }
557 }
558 FfiValue::Float(f) => Expr::Lit(crate::Literal::Str(f.to_string())),
559 FfiValue::Str(s) => Expr::Lit(crate::Literal::Str(s.clone())),
560 FfiValue::Bytes(bs) => Expr::Lit(crate::Literal::Str(
561 bs.iter().map(|b| format!("{:02x}", b)).collect::<String>(),
562 )),
563 FfiValue::Unit => Expr::Sort(crate::Level::zero()),
564 }
565 }
566}
567#[allow(dead_code)]
569pub struct StatSummary {
570 count: u64,
571 sum: f64,
572 min: f64,
573 max: f64,
574}
575#[allow(dead_code)]
576impl StatSummary {
577 pub fn new() -> Self {
579 Self {
580 count: 0,
581 sum: 0.0,
582 min: f64::INFINITY,
583 max: f64::NEG_INFINITY,
584 }
585 }
586 pub fn record(&mut self, val: f64) {
588 self.count += 1;
589 self.sum += val;
590 if val < self.min {
591 self.min = val;
592 }
593 if val > self.max {
594 self.max = val;
595 }
596 }
597 pub fn mean(&self) -> Option<f64> {
599 if self.count == 0 {
600 None
601 } else {
602 Some(self.sum / self.count as f64)
603 }
604 }
605 pub fn min(&self) -> Option<f64> {
607 if self.count == 0 {
608 None
609 } else {
610 Some(self.min)
611 }
612 }
613 pub fn max(&self) -> Option<f64> {
615 if self.count == 0 {
616 None
617 } else {
618 Some(self.max)
619 }
620 }
621 pub fn count(&self) -> u64 {
623 self.count
624 }
625}
626#[derive(Clone, PartialEq, Eq, Hash, Debug)]
630pub enum FfiType {
631 Bool,
633 UInt8,
635 UInt16,
637 UInt32,
639 UInt64,
641 Int8,
643 Int16,
645 Int32,
647 Int64,
649 Float32,
651 Float64,
653 String,
655 ByteArray,
657 Unit,
659 Ptr(Box<FfiType>),
661 Fn(Vec<FfiType>, Box<FfiType>),
663 OxiLean(String),
665}
666impl FfiType {
667 pub fn is_ffi_safe(&self) -> bool {
669 match self {
670 FfiType::Bool
671 | FfiType::UInt8
672 | FfiType::UInt16
673 | FfiType::UInt32
674 | FfiType::UInt64
675 | FfiType::Int8
676 | FfiType::Int16
677 | FfiType::Int32
678 | FfiType::Int64
679 | FfiType::Float32
680 | FfiType::Float64
681 | FfiType::String
682 | FfiType::ByteArray
683 | FfiType::Unit => true,
684 FfiType::Ptr(inner) => inner.is_ffi_safe(),
685 FfiType::Fn(params, ret) => params.iter().all(|t| t.is_ffi_safe()) && ret.is_ffi_safe(),
686 FfiType::OxiLean(_) => false,
687 }
688 }
689 pub fn size_bytes(&self) -> Option<usize> {
691 match self {
692 FfiType::Bool => Some(1),
693 FfiType::UInt8 | FfiType::Int8 => Some(1),
694 FfiType::UInt16 | FfiType::Int16 => Some(2),
695 FfiType::UInt32 | FfiType::Int32 => Some(4),
696 FfiType::UInt64 | FfiType::Int64 => Some(8),
697 FfiType::Float32 => Some(4),
698 FfiType::Float64 => Some(8),
699 FfiType::Unit => Some(0),
700 FfiType::Ptr(_) => Some(std::mem::size_of::<*const ()>()),
701 FfiType::String | FfiType::ByteArray => None,
702 FfiType::Fn(_, _) => Some(std::mem::size_of::<*const ()>()),
703 FfiType::OxiLean(_) => None,
704 }
705 }
706}
707#[allow(dead_code)]
709pub struct TransformStat {
710 before: StatSummary,
711 after: StatSummary,
712}
713#[allow(dead_code)]
714impl TransformStat {
715 pub fn new() -> Self {
717 Self {
718 before: StatSummary::new(),
719 after: StatSummary::new(),
720 }
721 }
722 pub fn record_before(&mut self, v: f64) {
724 self.before.record(v);
725 }
726 pub fn record_after(&mut self, v: f64) {
728 self.after.record(v);
729 }
730 pub fn mean_ratio(&self) -> Option<f64> {
732 let b = self.before.mean()?;
733 let a = self.after.mean()?;
734 if b.abs() < f64::EPSILON {
735 return None;
736 }
737 Some(a / b)
738 }
739}
740#[allow(dead_code)]
742pub struct StringPool {
743 free: Vec<String>,
744}
745#[allow(dead_code)]
746impl StringPool {
747 pub fn new() -> Self {
749 Self { free: Vec::new() }
750 }
751 pub fn take(&mut self) -> String {
753 self.free.pop().unwrap_or_default()
754 }
755 pub fn give(&mut self, mut s: String) {
757 s.clear();
758 self.free.push(s);
759 }
760 pub fn free_count(&self) -> usize {
762 self.free.len()
763 }
764}
765#[allow(dead_code)]
767pub struct SmallMap<K: Ord + Clone, V: Clone> {
768 entries: Vec<(K, V)>,
769}
770#[allow(dead_code)]
771impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
772 pub fn new() -> Self {
774 Self {
775 entries: Vec::new(),
776 }
777 }
778 pub fn insert(&mut self, key: K, val: V) {
780 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
781 Ok(i) => self.entries[i].1 = val,
782 Err(i) => self.entries.insert(i, (key, val)),
783 }
784 }
785 pub fn get(&self, key: &K) -> Option<&V> {
787 self.entries
788 .binary_search_by_key(&key, |(k, _)| k)
789 .ok()
790 .map(|i| &self.entries[i].1)
791 }
792 pub fn len(&self) -> usize {
794 self.entries.len()
795 }
796 pub fn is_empty(&self) -> bool {
798 self.entries.is_empty()
799 }
800 pub fn keys(&self) -> Vec<&K> {
802 self.entries.iter().map(|(k, _)| k).collect()
803 }
804 pub fn values(&self) -> Vec<&V> {
806 self.entries.iter().map(|(_, v)| v).collect()
807 }
808}
809#[allow(dead_code)]
811pub enum Either2<A, B> {
812 First(A),
814 Second(B),
816}
817#[allow(dead_code)]
818impl<A, B> Either2<A, B> {
819 pub fn is_first(&self) -> bool {
821 matches!(self, Either2::First(_))
822 }
823 pub fn is_second(&self) -> bool {
825 matches!(self, Either2::Second(_))
826 }
827 pub fn first(self) -> Option<A> {
829 match self {
830 Either2::First(a) => Some(a),
831 _ => None,
832 }
833 }
834 pub fn second(self) -> Option<B> {
836 match self {
837 Either2::Second(b) => Some(b),
838 _ => None,
839 }
840 }
841 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
843 match self {
844 Either2::First(a) => Either2::First(f(a)),
845 Either2::Second(b) => Either2::Second(b),
846 }
847 }
848}
849#[allow(dead_code)]
851pub struct SimpleDag {
852 edges: Vec<Vec<usize>>,
854}
855#[allow(dead_code)]
856impl SimpleDag {
857 pub fn new(n: usize) -> Self {
859 Self {
860 edges: vec![Vec::new(); n],
861 }
862 }
863 pub fn add_edge(&mut self, from: usize, to: usize) {
865 if from < self.edges.len() {
866 self.edges[from].push(to);
867 }
868 }
869 pub fn successors(&self, node: usize) -> &[usize] {
871 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
872 }
873 pub fn can_reach(&self, from: usize, to: usize) -> bool {
875 let mut visited = vec![false; self.edges.len()];
876 self.dfs(from, to, &mut visited)
877 }
878 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
879 if cur == target {
880 return true;
881 }
882 if cur >= visited.len() || visited[cur] {
883 return false;
884 }
885 visited[cur] = true;
886 for &next in self.successors(cur) {
887 if self.dfs(next, target, visited) {
888 return true;
889 }
890 }
891 false
892 }
893 pub fn topological_sort(&self) -> Option<Vec<usize>> {
895 let n = self.edges.len();
896 let mut in_degree = vec![0usize; n];
897 for succs in &self.edges {
898 for &s in succs {
899 if s < n {
900 in_degree[s] += 1;
901 }
902 }
903 }
904 let mut queue: std::collections::VecDeque<usize> =
905 (0..n).filter(|&i| in_degree[i] == 0).collect();
906 let mut order = Vec::new();
907 while let Some(node) = queue.pop_front() {
908 order.push(node);
909 for &s in self.successors(node) {
910 if s < n {
911 in_degree[s] -= 1;
912 if in_degree[s] == 0 {
913 queue.push_back(s);
914 }
915 }
916 }
917 }
918 if order.len() == n {
919 Some(order)
920 } else {
921 None
922 }
923 }
924 pub fn num_nodes(&self) -> usize {
926 self.edges.len()
927 }
928}
929#[derive(Clone, Debug)]
931pub struct FfiSignature {
932 pub params: Vec<FfiType>,
934 pub ret_type: Box<FfiType>,
936}
937impl FfiSignature {
938 pub fn new(params: Vec<FfiType>, ret_type: Box<FfiType>) -> Self {
940 FfiSignature { params, ret_type }
941 }
942 pub fn validate(&self) -> Result<(), FfiError> {
944 for param in &self.params {
945 if !param.is_ffi_safe() {
946 return Err(FfiError::InvalidSignature(format!(
947 "Unsafe parameter type: {}",
948 param
949 )));
950 }
951 }
952 if !self.ret_type.is_ffi_safe() {
953 return Err(FfiError::InvalidSignature(format!(
954 "Unsafe return type: {}",
955 self.ret_type
956 )));
957 }
958 Ok(())
959 }
960 pub fn matches_expr(&self, expr: &Expr) -> bool {
962 matches!(expr, Expr::Const(_, _))
963 }
964}
965#[allow(dead_code)]
967pub struct NonEmptyVec<T> {
968 head: T,
969 tail: Vec<T>,
970}
971#[allow(dead_code)]
972impl<T> NonEmptyVec<T> {
973 pub fn singleton(val: T) -> Self {
975 Self {
976 head: val,
977 tail: Vec::new(),
978 }
979 }
980 pub fn push(&mut self, val: T) {
982 self.tail.push(val);
983 }
984 pub fn first(&self) -> &T {
986 &self.head
987 }
988 pub fn last(&self) -> &T {
990 self.tail.last().unwrap_or(&self.head)
991 }
992 pub fn len(&self) -> usize {
994 1 + self.tail.len()
995 }
996 pub fn is_empty(&self) -> bool {
998 self.len() == 0
999 }
1000 pub fn to_vec(&self) -> Vec<&T> {
1002 let mut v = vec![&self.head];
1003 v.extend(self.tail.iter());
1004 v
1005 }
1006}
1007#[allow(dead_code)]
1009pub struct StackCalc {
1010 stack: Vec<i64>,
1011}
1012#[allow(dead_code)]
1013impl StackCalc {
1014 pub fn new() -> Self {
1016 Self { stack: Vec::new() }
1017 }
1018 pub fn push(&mut self, n: i64) {
1020 self.stack.push(n);
1021 }
1022 fn apply_binary(&mut self, op: impl FnOnce(i64, i64) -> i64) -> Option<i64> {
1026 let (rest_len, a, b) = match self.stack[..] {
1027 [ref rest @ .., a, b] => (rest.len(), a, b),
1028 _ => return None,
1029 };
1030 let value = op(a, b);
1031 self.stack.truncate(rest_len);
1032 self.stack.push(value);
1033 Some(value)
1034 }
1035 pub fn add(&mut self) -> Option<i64> {
1039 self.apply_binary(|a, b| a + b)
1040 }
1041 pub fn sub(&mut self) -> Option<i64> {
1045 self.apply_binary(|a, b| a - b)
1046 }
1047 pub fn mul(&mut self) -> Option<i64> {
1051 self.apply_binary(|a, b| a * b)
1052 }
1053 pub fn peek(&self) -> Option<i64> {
1055 self.stack.last().copied()
1056 }
1057 pub fn depth(&self) -> usize {
1059 self.stack.len()
1060 }
1061}
1062#[allow(dead_code)]
1064pub struct LabelSet {
1065 labels: Vec<String>,
1066}
1067#[allow(dead_code)]
1068impl LabelSet {
1069 pub fn new() -> Self {
1071 Self { labels: Vec::new() }
1072 }
1073 pub fn add(&mut self, label: impl Into<String>) {
1075 let s = label.into();
1076 if !self.labels.contains(&s) {
1077 self.labels.push(s);
1078 }
1079 }
1080 pub fn has(&self, label: &str) -> bool {
1082 self.labels.iter().any(|l| l == label)
1083 }
1084 pub fn count(&self) -> usize {
1086 self.labels.len()
1087 }
1088 pub fn all(&self) -> &[String] {
1090 &self.labels
1091 }
1092}
1093#[allow(dead_code)]
1095pub struct VersionedRecord<T: Clone> {
1096 earlier: Vec<T>,
1098 current: T,
1100}
1101#[allow(dead_code)]
1102impl<T: Clone> VersionedRecord<T> {
1103 pub fn new(initial: T) -> Self {
1105 Self {
1106 earlier: Vec::new(),
1107 current: initial,
1108 }
1109 }
1110 pub fn update(&mut self, val: T) {
1112 let previous = std::mem::replace(&mut self.current, val);
1113 self.earlier.push(previous);
1114 }
1115 pub fn current(&self) -> &T {
1117 &self.current
1118 }
1119 pub fn at_version(&self, n: usize) -> Option<&T> {
1121 match self.earlier.get(n) {
1122 Some(value) => Some(value),
1123 None if n == self.earlier.len() => Some(&self.current),
1124 None => None,
1125 }
1126 }
1127 pub fn version(&self) -> usize {
1129 self.earlier.len()
1130 }
1131 pub fn has_history(&self) -> bool {
1133 !self.earlier.is_empty()
1134 }
1135}
1136#[allow(dead_code)]
1138pub struct RewriteRuleSet {
1139 rules: Vec<RewriteRule>,
1140}
1141#[allow(dead_code)]
1142impl RewriteRuleSet {
1143 pub fn new() -> Self {
1145 Self { rules: Vec::new() }
1146 }
1147 pub fn add(&mut self, rule: RewriteRule) {
1149 self.rules.push(rule);
1150 }
1151 pub fn len(&self) -> usize {
1153 self.rules.len()
1154 }
1155 pub fn is_empty(&self) -> bool {
1157 self.rules.is_empty()
1158 }
1159 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
1161 self.rules.iter().filter(|r| r.conditional).collect()
1162 }
1163 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
1165 self.rules.iter().filter(|r| !r.conditional).collect()
1166 }
1167 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
1169 self.rules.iter().find(|r| r.name == name)
1170 }
1171}
1172#[derive(Clone, Debug)]
1174pub struct ExternDecl {
1175 pub name: Name,
1177 pub type_expr: Expr,
1179 pub lib_name: String,
1181 pub symbol_name: String,
1183 pub safety: FfiSafety,
1185 pub calling_convention: CallingConvention,
1187 pub signature: FfiSignature,
1189}
1190impl ExternDecl {
1191 pub fn new(
1193 name: Name,
1194 type_expr: Expr,
1195 lib_name: String,
1196 symbol_name: String,
1197 safety: FfiSafety,
1198 calling_convention: CallingConvention,
1199 signature: FfiSignature,
1200 ) -> Self {
1201 ExternDecl {
1202 name,
1203 type_expr,
1204 lib_name,
1205 symbol_name,
1206 safety,
1207 calling_convention,
1208 signature,
1209 }
1210 }
1211 pub fn validate(&self) -> Result<(), FfiError> {
1213 self.signature.validate()?;
1214 if self.lib_name.is_empty() {
1215 return Err(FfiError::InvalidSignature(
1216 "Library name cannot be empty".to_string(),
1217 ));
1218 }
1219 if self.symbol_name.is_empty() {
1220 return Err(FfiError::InvalidSignature(
1221 "Symbol name cannot be empty".to_string(),
1222 ));
1223 }
1224 Ok(())
1225 }
1226}
1227pub struct BuiltinExterns;
1229impl BuiltinExterns {
1230 pub fn register_builtins(registry: &mut ExternRegistry) -> Result<(), FfiError> {
1232 Self::register_io(registry)?;
1233 Self::register_string(registry)?;
1234 Self::register_arithmetic(registry)?;
1235 Ok(())
1236 }
1237 pub(crate) fn register_io(registry: &mut ExternRegistry) -> Result<(), FfiError> {
1239 registry.register(ExternDecl::new(
1240 Name::str("builtin_print"),
1241 Expr::Const(Name::str("String"), vec![]),
1242 "libc".to_string(),
1243 "puts".to_string(),
1244 FfiSafety::System,
1245 CallingConvention::C,
1246 FfiSignature::new(vec![FfiType::String], Box::new(FfiType::Int32)),
1247 ))?;
1248 registry.register(ExternDecl::new(
1249 Name::str("builtin_print_int"),
1250 Expr::Const(Name::str("Nat"), vec![]),
1251 "libc".to_string(),
1252 "printf".to_string(),
1253 FfiSafety::System,
1254 CallingConvention::C,
1255 FfiSignature::new(
1256 vec![FfiType::String, FfiType::UInt64],
1257 Box::new(FfiType::Int32),
1258 ),
1259 ))?;
1260 Ok(())
1261 }
1262 pub(crate) fn register_string(registry: &mut ExternRegistry) -> Result<(), FfiError> {
1264 registry.register(ExternDecl::new(
1265 Name::str("builtin_strlen"),
1266 Expr::Const(Name::str("String"), vec![]),
1267 "libc".to_string(),
1268 "strlen".to_string(),
1269 FfiSafety::Unsafe,
1270 CallingConvention::C,
1271 FfiSignature::new(vec![FfiType::String], Box::new(FfiType::UInt64)),
1272 ))?;
1273 registry.register(ExternDecl::new(
1274 Name::str("builtin_strcmp"),
1275 Expr::Const(Name::str("String"), vec![]),
1276 "libc".to_string(),
1277 "strcmp".to_string(),
1278 FfiSafety::Unsafe,
1279 CallingConvention::C,
1280 FfiSignature::new(
1281 vec![FfiType::String, FfiType::String],
1282 Box::new(FfiType::Int32),
1283 ),
1284 ))?;
1285 Ok(())
1286 }
1287 pub(crate) fn register_arithmetic(registry: &mut ExternRegistry) -> Result<(), FfiError> {
1289 registry.register(ExternDecl::new(
1290 Name::str("builtin_abs"),
1291 Expr::Const(Name::str("Int"), vec![]),
1292 "libc".to_string(),
1293 "abs".to_string(),
1294 FfiSafety::Safe,
1295 CallingConvention::C,
1296 FfiSignature::new(vec![FfiType::Int32], Box::new(FfiType::Int32)),
1297 ))?;
1298 registry.register(ExternDecl::new(
1299 Name::str("builtin_sqrt"),
1300 Expr::Const(Name::str("Float"), vec![]),
1301 "libm".to_string(),
1302 "sqrt".to_string(),
1303 FfiSafety::Safe,
1304 CallingConvention::C,
1305 FfiSignature::new(vec![FfiType::Float64], Box::new(FfiType::Float64)),
1306 ))?;
1307 Ok(())
1308 }
1309}
1310#[derive(Clone, Debug, PartialEq, Eq)]
1312pub struct LibraryVersion {
1313 pub name: String,
1315 pub major: u32,
1317 pub minor: u32,
1319 pub patch: u32,
1321}
1322impl LibraryVersion {
1323 pub fn new(name: &str, major: u32, minor: u32, patch: u32) -> Self {
1325 Self {
1326 name: name.to_string(),
1327 major,
1328 minor,
1329 patch,
1330 }
1331 }
1332 pub fn at_least(&self, major: u32, minor: u32, patch: u32) -> bool {
1334 (self.major, self.minor, self.patch) >= (major, minor, patch)
1335 }
1336}
1337#[derive(Clone, Debug)]
1339pub struct SymbolMetadata {
1340 pub symbol: String,
1342 pub library: String,
1344 pub weak: bool,
1346 pub thread_local: bool,
1348}
1349impl SymbolMetadata {
1350 pub fn new(symbol: &str, library: &str) -> Self {
1352 Self {
1353 symbol: symbol.to_string(),
1354 library: library.to_string(),
1355 weak: false,
1356 thread_local: false,
1357 }
1358 }
1359 pub fn with_weak(mut self) -> Self {
1361 self.weak = true;
1362 self
1363 }
1364 pub fn with_thread_local(mut self) -> Self {
1366 self.thread_local = true;
1367 self
1368 }
1369}
1370#[allow(dead_code)]
1372pub struct RawFnPtr {
1373 ptr: usize,
1375 arity: usize,
1376 name: String,
1377}
1378#[allow(dead_code)]
1379impl RawFnPtr {
1380 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
1382 Self {
1383 ptr,
1384 arity,
1385 name: name.into(),
1386 }
1387 }
1388 pub fn arity(&self) -> usize {
1390 self.arity
1391 }
1392 pub fn name(&self) -> &str {
1394 &self.name
1395 }
1396 pub fn raw(&self) -> usize {
1398 self.ptr
1399 }
1400}
1401#[allow(dead_code)]
1403pub struct TransitiveClosure {
1404 adj: Vec<Vec<usize>>,
1405 n: usize,
1406}
1407#[allow(dead_code)]
1408impl TransitiveClosure {
1409 pub fn new(n: usize) -> Self {
1411 Self {
1412 adj: vec![Vec::new(); n],
1413 n,
1414 }
1415 }
1416 pub fn add_edge(&mut self, from: usize, to: usize) {
1418 if from < self.n {
1419 self.adj[from].push(to);
1420 }
1421 }
1422 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
1424 let mut visited = vec![false; self.n];
1425 let mut queue = std::collections::VecDeque::new();
1426 queue.push_back(start);
1427 while let Some(node) = queue.pop_front() {
1428 if node >= self.n || visited[node] {
1429 continue;
1430 }
1431 visited[node] = true;
1432 for &next in &self.adj[node] {
1433 queue.push_back(next);
1434 }
1435 }
1436 (0..self.n).filter(|&i| visited[i]).collect()
1437 }
1438 pub fn can_reach(&self, from: usize, to: usize) -> bool {
1440 self.reachable_from(from).contains(&to)
1441 }
1442}
1443#[allow(dead_code)]
1445pub struct FlatSubstitution {
1446 pairs: Vec<(String, String)>,
1447}
1448#[allow(dead_code)]
1449impl FlatSubstitution {
1450 pub fn new() -> Self {
1452 Self { pairs: Vec::new() }
1453 }
1454 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
1456 self.pairs.push((from.into(), to.into()));
1457 }
1458 pub fn apply(&self, s: &str) -> String {
1460 let mut result = s.to_string();
1461 for (from, to) in &self.pairs {
1462 result = result.replace(from.as_str(), to.as_str());
1463 }
1464 result
1465 }
1466 pub fn len(&self) -> usize {
1468 self.pairs.len()
1469 }
1470 pub fn is_empty(&self) -> bool {
1472 self.pairs.is_empty()
1473 }
1474}
1475pub struct ExternRegistry {
1477 decls: HashMap<(String, String), ExternDecl>,
1479 name_map: HashMap<String, (String, String)>,
1481}
1482impl ExternRegistry {
1483 pub fn new() -> Self {
1485 ExternRegistry {
1486 decls: HashMap::new(),
1487 name_map: HashMap::new(),
1488 }
1489 }
1490 pub fn register(&mut self, decl: ExternDecl) -> Result<(), FfiError> {
1492 decl.validate()?;
1493 let key = (decl.lib_name.clone(), decl.symbol_name.clone());
1494 if self.decls.contains_key(&key) {
1495 return Err(FfiError::DuplicateSymbol(format!(
1496 "{}::{}",
1497 decl.lib_name, decl.symbol_name
1498 )));
1499 }
1500 let name_str = decl.name.to_string();
1501 if self.name_map.contains_key(&name_str) {
1502 return Err(FfiError::DuplicateSymbol(name_str));
1503 }
1504 self.name_map.insert(name_str, key.clone());
1505 self.decls.insert(key, decl);
1506 Ok(())
1507 }
1508 pub fn lookup(&self, name: &Name) -> Result<&ExternDecl, FfiError> {
1510 let name_str = name.to_string();
1511 let key = self
1512 .name_map
1513 .get(&name_str)
1514 .ok_or_else(|| FfiError::SymbolNotFound(name_str.clone()))?;
1515 self.decls
1516 .get(key)
1517 .ok_or(FfiError::SymbolNotFound(name_str))
1518 }
1519 pub fn lookup_by_symbol(
1521 &self,
1522 lib_name: &str,
1523 symbol_name: &str,
1524 ) -> Result<&ExternDecl, FfiError> {
1525 let key = (lib_name.to_string(), symbol_name.to_string());
1526 self.decls
1527 .get(&key)
1528 .ok_or_else(|| FfiError::SymbolNotFound(format!("{}::{}", lib_name, symbol_name)))
1529 }
1530 pub fn validate_all(&self) -> Result<(), FfiError> {
1532 for decl in self.decls.values() {
1533 decl.validate()?;
1534 }
1535 Ok(())
1536 }
1537 pub fn all_decls(&self) -> impl Iterator<Item = &ExternDecl> {
1539 self.decls.values()
1540 }
1541 pub fn count(&self) -> usize {
1543 self.decls.len()
1544 }
1545}
1546#[allow(dead_code)]
1548pub struct TokenBucket {
1549 capacity: u64,
1550 tokens: u64,
1551 refill_per_ms: u64,
1552 last_refill: crate::wall_clock::Instant,
1553}
1554#[allow(dead_code)]
1555impl TokenBucket {
1556 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
1558 Self {
1559 capacity,
1560 tokens: capacity,
1561 refill_per_ms,
1562 last_refill: crate::wall_clock::Instant::now(),
1563 }
1564 }
1565 pub fn try_consume(&mut self, n: u64) -> bool {
1567 self.refill();
1568 if self.tokens >= n {
1569 self.tokens -= n;
1570 true
1571 } else {
1572 false
1573 }
1574 }
1575 fn refill(&mut self) {
1576 let now = crate::wall_clock::Instant::now();
1577 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
1578 if elapsed_ms > 0 {
1579 let new_tokens = elapsed_ms * self.refill_per_ms;
1580 self.tokens = (self.tokens + new_tokens).min(self.capacity);
1581 self.last_refill = now;
1582 }
1583 }
1584 pub fn available(&self) -> u64 {
1586 self.tokens
1587 }
1588 pub fn capacity(&self) -> u64 {
1590 self.capacity
1591 }
1592}
1593#[allow(dead_code)]
1595pub struct PrefixCounter {
1596 children: std::collections::HashMap<char, PrefixCounter>,
1597 count: usize,
1598}
1599#[allow(dead_code)]
1600impl PrefixCounter {
1601 pub fn new() -> Self {
1603 Self {
1604 children: std::collections::HashMap::new(),
1605 count: 0,
1606 }
1607 }
1608 pub fn record(&mut self, s: &str) {
1610 self.count += 1;
1611 let mut node = self;
1612 for c in s.chars() {
1613 node = node.children.entry(c).or_default();
1614 node.count += 1;
1615 }
1616 }
1617 pub fn count_with_prefix(&self, prefix: &str) -> usize {
1619 let mut node = self;
1620 for c in prefix.chars() {
1621 match node.children.get(&c) {
1622 Some(n) => node = n,
1623 None => return 0,
1624 }
1625 }
1626 node.count
1627 }
1628}
1629#[allow(dead_code)]
1631pub struct FocusStack<T> {
1632 items: Vec<T>,
1633}
1634#[allow(dead_code)]
1635impl<T> FocusStack<T> {
1636 pub fn new() -> Self {
1638 Self { items: Vec::new() }
1639 }
1640 pub fn focus(&mut self, item: T) {
1642 self.items.push(item);
1643 }
1644 pub fn blur(&mut self) -> Option<T> {
1646 self.items.pop()
1647 }
1648 pub fn current(&self) -> Option<&T> {
1650 self.items.last()
1651 }
1652 pub fn depth(&self) -> usize {
1654 self.items.len()
1655 }
1656 pub fn is_empty(&self) -> bool {
1658 self.items.is_empty()
1659 }
1660}
1661#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
1663pub enum CallingConvention {
1664 Rust,
1666 C,
1668 System,
1670}
1671#[derive(Clone, PartialEq, Eq, Hash, Debug)]
1673pub enum FfiError {
1674 SymbolNotFound(String),
1676 LibraryNotFound(String),
1678 TypeMismatch(String),
1680 ValueOutOfRange(String),
1682 InvalidSignature(String),
1684 DuplicateSymbol(String),
1686 ValidationFailed(String),
1688}
1689#[derive(Clone, Debug, Default)]
1691pub struct LibraryManifest {
1692 pub entries: Vec<LibraryVersion>,
1694}
1695impl LibraryManifest {
1696 pub fn new() -> Self {
1698 Self::default()
1699 }
1700 pub fn require(&mut self, lib: LibraryVersion) {
1702 self.entries.push(lib);
1703 }
1704 pub fn requires_lib(&self, name: &str) -> bool {
1706 self.entries.iter().any(|l| l.name == name)
1707 }
1708 pub fn len(&self) -> usize {
1710 self.entries.len()
1711 }
1712 pub fn is_empty(&self) -> bool {
1714 self.entries.is_empty()
1715 }
1716}