1use crate::{BinderInfo, Declaration, Environment, Expr, Level, Name};
6
7use std::collections::HashMap;
8
9#[allow(dead_code)]
11#[allow(missing_docs)]
12pub enum DecisionNode {
13 Leaf(String),
15 Branch {
17 key: String,
18 val: String,
19 yes_branch: Box<DecisionNode>,
20 no_branch: Box<DecisionNode>,
21 },
22}
23#[allow(dead_code)]
24impl DecisionNode {
25 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
27 match self {
28 DecisionNode::Leaf(action) => action.as_str(),
29 DecisionNode::Branch {
30 key,
31 val,
32 yes_branch,
33 no_branch,
34 } => {
35 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
36 if actual == val.as_str() {
37 yes_branch.evaluate(ctx)
38 } else {
39 no_branch.evaluate(ctx)
40 }
41 }
42 }
43 }
44 pub fn depth(&self) -> usize {
46 match self {
47 DecisionNode::Leaf(_) => 0,
48 DecisionNode::Branch {
49 yes_branch,
50 no_branch,
51 ..
52 } => 1 + yes_branch.depth().max(no_branch.depth()),
53 }
54 }
55}
56#[allow(dead_code)]
58pub struct TokenBucket {
59 capacity: u64,
60 tokens: u64,
61 refill_per_ms: u64,
62 last_refill: crate::wall_clock::Instant,
63}
64#[allow(dead_code)]
65impl TokenBucket {
66 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
68 Self {
69 capacity,
70 tokens: capacity,
71 refill_per_ms,
72 last_refill: crate::wall_clock::Instant::now(),
73 }
74 }
75 pub fn try_consume(&mut self, n: u64) -> bool {
77 self.refill();
78 if self.tokens >= n {
79 self.tokens -= n;
80 true
81 } else {
82 false
83 }
84 }
85 fn refill(&mut self) {
86 let now = crate::wall_clock::Instant::now();
87 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
88 if elapsed_ms > 0 {
89 let new_tokens = elapsed_ms * self.refill_per_ms;
90 self.tokens = (self.tokens + new_tokens).min(self.capacity);
91 self.last_refill = now;
92 }
93 }
94 pub fn available(&self) -> u64 {
96 self.tokens
97 }
98 pub fn capacity(&self) -> u64 {
100 self.capacity
101 }
102}
103#[allow(dead_code)]
105pub struct StackCalc {
106 stack: Vec<i64>,
107}
108#[allow(dead_code)]
109impl StackCalc {
110 pub fn new() -> Self {
112 Self { stack: Vec::new() }
113 }
114 pub fn push(&mut self, n: i64) {
116 self.stack.push(n);
117 }
118 fn apply_binary(&mut self, op: impl FnOnce(i64, i64) -> i64) -> Option<i64> {
122 let (rest_len, a, b) = match self.stack[..] {
123 [ref rest @ .., a, b] => (rest.len(), a, b),
124 _ => return None,
125 };
126 let value = op(a, b);
127 self.stack.truncate(rest_len);
128 self.stack.push(value);
129 Some(value)
130 }
131 pub fn add(&mut self) -> Option<i64> {
135 self.apply_binary(|a, b| a + b)
136 }
137 pub fn sub(&mut self) -> Option<i64> {
141 self.apply_binary(|a, b| a - b)
142 }
143 pub fn mul(&mut self) -> Option<i64> {
147 self.apply_binary(|a, b| a * b)
148 }
149 pub fn peek(&self) -> Option<i64> {
151 self.stack.last().copied()
152 }
153 pub fn depth(&self) -> usize {
155 self.stack.len()
156 }
157}
158#[allow(dead_code)]
160pub enum Either2<A, B> {
161 First(A),
163 Second(B),
165}
166#[allow(dead_code)]
167impl<A, B> Either2<A, B> {
168 pub fn is_first(&self) -> bool {
170 matches!(self, Either2::First(_))
171 }
172 pub fn is_second(&self) -> bool {
174 matches!(self, Either2::Second(_))
175 }
176 pub fn first(self) -> Option<A> {
178 match self {
179 Either2::First(a) => Some(a),
180 _ => None,
181 }
182 }
183 pub fn second(self) -> Option<B> {
185 match self {
186 Either2::Second(b) => Some(b),
187 _ => None,
188 }
189 }
190 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
192 match self {
193 Either2::First(a) => Either2::First(f(a)),
194 Either2::Second(b) => Either2::Second(b),
195 }
196 }
197}
198#[allow(dead_code)]
200pub struct RawFnPtr {
201 ptr: usize,
203 arity: usize,
204 name: String,
205}
206#[allow(dead_code)]
207impl RawFnPtr {
208 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
210 Self {
211 ptr,
212 arity,
213 name: name.into(),
214 }
215 }
216 pub fn arity(&self) -> usize {
218 self.arity
219 }
220 pub fn name(&self) -> &str {
222 &self.name
223 }
224 pub fn raw(&self) -> usize {
226 self.ptr
227 }
228}
229#[allow(dead_code)]
231pub struct PathBuf {
232 components: Vec<String>,
233}
234#[allow(dead_code)]
235impl PathBuf {
236 pub fn new() -> Self {
238 Self {
239 components: Vec::new(),
240 }
241 }
242 pub fn push(&mut self, comp: impl Into<String>) {
244 self.components.push(comp.into());
245 }
246 pub fn pop(&mut self) {
248 self.components.pop();
249 }
250 pub fn as_str(&self) -> String {
252 self.components.join("/")
253 }
254 pub fn depth(&self) -> usize {
256 self.components.len()
257 }
258 pub fn clear(&mut self) {
260 self.components.clear();
261 }
262}
263#[allow(dead_code)]
265pub struct StringPool {
266 free: Vec<String>,
267}
268#[allow(dead_code)]
269impl StringPool {
270 pub fn new() -> Self {
272 Self { free: Vec::new() }
273 }
274 pub fn take(&mut self) -> String {
276 self.free.pop().unwrap_or_default()
277 }
278 pub fn give(&mut self, mut s: String) {
280 s.clear();
281 self.free.push(s);
282 }
283 pub fn free_count(&self) -> usize {
285 self.free.len()
286 }
287}
288#[allow(dead_code)]
290pub struct Stopwatch {
291 start: crate::wall_clock::Instant,
292 splits: Vec<f64>,
293}
294#[allow(dead_code)]
295impl Stopwatch {
296 pub fn start() -> Self {
298 Self {
299 start: crate::wall_clock::Instant::now(),
300 splits: Vec::new(),
301 }
302 }
303 pub fn split(&mut self) {
305 self.splits.push(self.elapsed_ms());
306 }
307 pub fn elapsed_ms(&self) -> f64 {
309 self.start.elapsed().as_secs_f64() * 1000.0
310 }
311 pub fn splits(&self) -> &[f64] {
313 &self.splits
314 }
315 pub fn num_splits(&self) -> usize {
317 self.splits.len()
318 }
319}
320#[allow(dead_code)]
322pub struct TransitiveClosure {
323 adj: Vec<Vec<usize>>,
324 n: usize,
325}
326#[allow(dead_code)]
327impl TransitiveClosure {
328 pub fn new(n: usize) -> Self {
330 Self {
331 adj: vec![Vec::new(); n],
332 n,
333 }
334 }
335 pub fn add_edge(&mut self, from: usize, to: usize) {
337 if from < self.n {
338 self.adj[from].push(to);
339 }
340 }
341 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
343 let mut visited = vec![false; self.n];
344 let mut queue = std::collections::VecDeque::new();
345 queue.push_back(start);
346 while let Some(node) = queue.pop_front() {
347 if node >= self.n || visited[node] {
348 continue;
349 }
350 visited[node] = true;
351 for &next in &self.adj[node] {
352 queue.push_back(next);
353 }
354 }
355 (0..self.n).filter(|&i| visited[i]).collect()
356 }
357 pub fn can_reach(&self, from: usize, to: usize) -> bool {
359 self.reachable_from(from).contains(&to)
360 }
361}
362#[allow(dead_code)]
364#[derive(Debug, Clone)]
365pub struct BuiltinInfo {
366 pub name: &'static str,
368 pub kind: BuiltinKind,
370 pub description: &'static str,
372}
373#[allow(dead_code)]
375#[allow(missing_docs)]
376pub struct RewriteRule {
377 pub name: String,
379 pub lhs: String,
381 pub rhs: String,
383 pub conditional: bool,
385}
386#[allow(dead_code)]
387impl RewriteRule {
388 pub fn unconditional(
390 name: impl Into<String>,
391 lhs: impl Into<String>,
392 rhs: impl Into<String>,
393 ) -> Self {
394 Self {
395 name: name.into(),
396 lhs: lhs.into(),
397 rhs: rhs.into(),
398 conditional: false,
399 }
400 }
401 pub fn conditional(
403 name: impl Into<String>,
404 lhs: impl Into<String>,
405 rhs: impl Into<String>,
406 ) -> Self {
407 Self {
408 name: name.into(),
409 lhs: lhs.into(),
410 rhs: rhs.into(),
411 conditional: true,
412 }
413 }
414 pub fn display(&self) -> String {
416 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
417 }
418}
419#[allow(dead_code)]
421pub struct SlidingSum {
422 window: Vec<f64>,
423 capacity: usize,
424 pos: usize,
425 sum: f64,
426 count: usize,
427}
428#[allow(dead_code)]
429impl SlidingSum {
430 pub fn new(capacity: usize) -> Self {
432 Self {
433 window: vec![0.0; capacity],
434 capacity,
435 pos: 0,
436 sum: 0.0,
437 count: 0,
438 }
439 }
440 pub fn push(&mut self, val: f64) {
442 let oldest = self.window[self.pos];
443 self.sum -= oldest;
444 self.sum += val;
445 self.window[self.pos] = val;
446 self.pos = (self.pos + 1) % self.capacity;
447 if self.count < self.capacity {
448 self.count += 1;
449 }
450 }
451 pub fn sum(&self) -> f64 {
453 self.sum
454 }
455 pub fn mean(&self) -> Option<f64> {
457 if self.count == 0 {
458 None
459 } else {
460 Some(self.sum / self.count as f64)
461 }
462 }
463 pub fn count(&self) -> usize {
465 self.count
466 }
467}
468#[allow(dead_code)]
470pub struct SparseVec<T: Default + Clone + PartialEq> {
471 entries: std::collections::HashMap<usize, T>,
472 default_: T,
473 logical_len: usize,
474}
475#[allow(dead_code)]
476impl<T: Default + Clone + PartialEq> SparseVec<T> {
477 pub fn new(len: usize) -> Self {
479 Self {
480 entries: std::collections::HashMap::new(),
481 default_: T::default(),
482 logical_len: len,
483 }
484 }
485 pub fn set(&mut self, idx: usize, val: T) {
487 if val == self.default_ {
488 self.entries.remove(&idx);
489 } else {
490 self.entries.insert(idx, val);
491 }
492 }
493 pub fn get(&self, idx: usize) -> &T {
495 self.entries.get(&idx).unwrap_or(&self.default_)
496 }
497 pub fn len(&self) -> usize {
499 self.logical_len
500 }
501 pub fn is_empty(&self) -> bool {
503 self.len() == 0
504 }
505 pub fn nnz(&self) -> usize {
507 self.entries.len()
508 }
509}
510#[allow(dead_code)]
512pub struct SmallMap<K: Ord + Clone, V: Clone> {
513 entries: Vec<(K, V)>,
514}
515#[allow(dead_code)]
516impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
517 pub fn new() -> Self {
519 Self {
520 entries: Vec::new(),
521 }
522 }
523 pub fn insert(&mut self, key: K, val: V) {
525 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
526 Ok(i) => self.entries[i].1 = val,
527 Err(i) => self.entries.insert(i, (key, val)),
528 }
529 }
530 pub fn get(&self, key: &K) -> Option<&V> {
532 self.entries
533 .binary_search_by_key(&key, |(k, _)| k)
534 .ok()
535 .map(|i| &self.entries[i].1)
536 }
537 pub fn len(&self) -> usize {
539 self.entries.len()
540 }
541 pub fn is_empty(&self) -> bool {
543 self.entries.is_empty()
544 }
545 pub fn keys(&self) -> Vec<&K> {
547 self.entries.iter().map(|(k, _)| k).collect()
548 }
549 pub fn values(&self) -> Vec<&V> {
551 self.entries.iter().map(|(_, v)| v).collect()
552 }
553}
554#[allow(dead_code)]
556pub struct StatSummary {
557 count: u64,
558 sum: f64,
559 min: f64,
560 max: f64,
561}
562#[allow(dead_code)]
563impl StatSummary {
564 pub fn new() -> Self {
566 Self {
567 count: 0,
568 sum: 0.0,
569 min: f64::INFINITY,
570 max: f64::NEG_INFINITY,
571 }
572 }
573 pub fn record(&mut self, val: f64) {
575 self.count += 1;
576 self.sum += val;
577 if val < self.min {
578 self.min = val;
579 }
580 if val > self.max {
581 self.max = val;
582 }
583 }
584 pub fn mean(&self) -> Option<f64> {
586 if self.count == 0 {
587 None
588 } else {
589 Some(self.sum / self.count as f64)
590 }
591 }
592 pub fn min(&self) -> Option<f64> {
594 if self.count == 0 {
595 None
596 } else {
597 Some(self.min)
598 }
599 }
600 pub fn max(&self) -> Option<f64> {
602 if self.count == 0 {
603 None
604 } else {
605 Some(self.max)
606 }
607 }
608 pub fn count(&self) -> u64 {
610 self.count
611 }
612}
613#[allow(dead_code)]
615pub struct SimpleDag {
616 edges: Vec<Vec<usize>>,
618}
619#[allow(dead_code)]
620impl SimpleDag {
621 pub fn new(n: usize) -> Self {
623 Self {
624 edges: vec![Vec::new(); n],
625 }
626 }
627 pub fn add_edge(&mut self, from: usize, to: usize) {
629 if from < self.edges.len() {
630 self.edges[from].push(to);
631 }
632 }
633 pub fn successors(&self, node: usize) -> &[usize] {
635 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
636 }
637 pub fn can_reach(&self, from: usize, to: usize) -> bool {
639 let mut visited = vec![false; self.edges.len()];
640 self.dfs(from, to, &mut visited)
641 }
642 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
643 if cur == target {
644 return true;
645 }
646 if cur >= visited.len() || visited[cur] {
647 return false;
648 }
649 visited[cur] = true;
650 for &next in self.successors(cur) {
651 if self.dfs(next, target, visited) {
652 return true;
653 }
654 }
655 false
656 }
657 pub fn topological_sort(&self) -> Option<Vec<usize>> {
659 let n = self.edges.len();
660 let mut in_degree = vec![0usize; n];
661 for succs in &self.edges {
662 for &s in succs {
663 if s < n {
664 in_degree[s] += 1;
665 }
666 }
667 }
668 let mut queue: std::collections::VecDeque<usize> =
669 (0..n).filter(|&i| in_degree[i] == 0).collect();
670 let mut order = Vec::new();
671 while let Some(node) = queue.pop_front() {
672 order.push(node);
673 for &s in self.successors(node) {
674 if s < n {
675 in_degree[s] -= 1;
676 if in_degree[s] == 0 {
677 queue.push_back(s);
678 }
679 }
680 }
681 }
682 if order.len() == n {
683 Some(order)
684 } else {
685 None
686 }
687 }
688 pub fn num_nodes(&self) -> usize {
690 self.edges.len()
691 }
692}
693#[allow(dead_code)]
695pub struct ConfigNode {
696 key: String,
697 value: Option<String>,
698 children: Vec<ConfigNode>,
699}
700#[allow(dead_code)]
701impl ConfigNode {
702 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
704 Self {
705 key: key.into(),
706 value: Some(value.into()),
707 children: Vec::new(),
708 }
709 }
710 pub fn section(key: impl Into<String>) -> Self {
712 Self {
713 key: key.into(),
714 value: None,
715 children: Vec::new(),
716 }
717 }
718 pub fn add_child(&mut self, child: ConfigNode) {
720 self.children.push(child);
721 }
722 pub fn key(&self) -> &str {
724 &self.key
725 }
726 pub fn value(&self) -> Option<&str> {
728 self.value.as_deref()
729 }
730 pub fn num_children(&self) -> usize {
732 self.children.len()
733 }
734 pub fn lookup(&self, path: &str) -> Option<&str> {
736 let mut parts = path.splitn(2, '.');
737 let head = parts.next()?;
738 let tail = parts.next();
739 if head != self.key {
740 return None;
741 }
742 match tail {
743 None => self.value.as_deref(),
744 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
745 }
746 }
747 fn lookup_relative(&self, path: &str) -> Option<&str> {
748 let mut parts = path.splitn(2, '.');
749 let head = parts.next()?;
750 let tail = parts.next();
751 if head != self.key {
752 return None;
753 }
754 match tail {
755 None => self.value.as_deref(),
756 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
757 }
758 }
759}
760#[allow(dead_code)]
762pub struct VersionedRecord<T: Clone> {
763 earlier: Vec<T>,
765 current: T,
767}
768#[allow(dead_code)]
769impl<T: Clone> VersionedRecord<T> {
770 pub fn new(initial: T) -> Self {
772 Self {
773 earlier: Vec::new(),
774 current: initial,
775 }
776 }
777 pub fn update(&mut self, val: T) {
779 let previous = std::mem::replace(&mut self.current, val);
780 self.earlier.push(previous);
781 }
782 pub fn current(&self) -> &T {
784 &self.current
785 }
786 pub fn at_version(&self, n: usize) -> Option<&T> {
788 match self.earlier.get(n) {
789 Some(value) => Some(value),
790 None if n == self.earlier.len() => Some(&self.current),
791 None => None,
792 }
793 }
794 pub fn version(&self) -> usize {
796 self.earlier.len()
797 }
798 pub fn has_history(&self) -> bool {
800 !self.earlier.is_empty()
801 }
802}
803#[allow(dead_code)]
805pub struct LabelSet {
806 labels: Vec<String>,
807}
808#[allow(dead_code)]
809impl LabelSet {
810 pub fn new() -> Self {
812 Self { labels: Vec::new() }
813 }
814 pub fn add(&mut self, label: impl Into<String>) {
816 let s = label.into();
817 if !self.labels.contains(&s) {
818 self.labels.push(s);
819 }
820 }
821 pub fn has(&self, label: &str) -> bool {
823 self.labels.iter().any(|l| l == label)
824 }
825 pub fn count(&self) -> usize {
827 self.labels.len()
828 }
829 pub fn all(&self) -> &[String] {
831 &self.labels
832 }
833}
834#[allow(dead_code)]
836pub struct TransformStat {
837 before: StatSummary,
838 after: StatSummary,
839}
840#[allow(dead_code)]
841impl TransformStat {
842 pub fn new() -> Self {
844 Self {
845 before: StatSummary::new(),
846 after: StatSummary::new(),
847 }
848 }
849 pub fn record_before(&mut self, v: f64) {
851 self.before.record(v);
852 }
853 pub fn record_after(&mut self, v: f64) {
855 self.after.record(v);
856 }
857 pub fn mean_ratio(&self) -> Option<f64> {
859 let b = self.before.mean()?;
860 let a = self.after.mean()?;
861 if b.abs() < f64::EPSILON {
862 return None;
863 }
864 Some(a / b)
865 }
866}
867#[allow(dead_code)]
869pub struct FocusStack<T> {
870 items: Vec<T>,
871}
872#[allow(dead_code)]
873impl<T> FocusStack<T> {
874 pub fn new() -> Self {
876 Self { items: Vec::new() }
877 }
878 pub fn focus(&mut self, item: T) {
880 self.items.push(item);
881 }
882 pub fn blur(&mut self) -> Option<T> {
884 self.items.pop()
885 }
886 pub fn current(&self) -> Option<&T> {
888 self.items.last()
889 }
890 pub fn depth(&self) -> usize {
892 self.items.len()
893 }
894 pub fn is_empty(&self) -> bool {
896 self.items.is_empty()
897 }
898}
899#[allow(dead_code)]
901pub struct WindowIterator<'a, T> {
902 pub(super) data: &'a [T],
903 pub(super) pos: usize,
904 pub(super) window: usize,
905}
906#[allow(dead_code)]
907impl<'a, T> WindowIterator<'a, T> {
908 pub fn new(data: &'a [T], window: usize) -> Self {
910 Self {
911 data,
912 pos: 0,
913 window,
914 }
915 }
916}
917#[allow(dead_code)]
919pub struct NonEmptyVec<T> {
920 head: T,
921 tail: Vec<T>,
922}
923#[allow(dead_code)]
924impl<T> NonEmptyVec<T> {
925 pub fn singleton(val: T) -> Self {
927 Self {
928 head: val,
929 tail: Vec::new(),
930 }
931 }
932 pub fn push(&mut self, val: T) {
934 self.tail.push(val);
935 }
936 pub fn first(&self) -> &T {
938 &self.head
939 }
940 pub fn last(&self) -> &T {
942 self.tail.last().unwrap_or(&self.head)
943 }
944 pub fn len(&self) -> usize {
946 1 + self.tail.len()
947 }
948 pub fn is_empty(&self) -> bool {
950 self.len() == 0
951 }
952 pub fn to_vec(&self) -> Vec<&T> {
954 let mut v = vec![&self.head];
955 v.extend(self.tail.iter());
956 v
957 }
958}
959#[allow(dead_code)]
961pub struct RewriteRuleSet {
962 rules: Vec<RewriteRule>,
963}
964#[allow(dead_code)]
965impl RewriteRuleSet {
966 pub fn new() -> Self {
968 Self { rules: Vec::new() }
969 }
970 pub fn add(&mut self, rule: RewriteRule) {
972 self.rules.push(rule);
973 }
974 pub fn len(&self) -> usize {
976 self.rules.len()
977 }
978 pub fn is_empty(&self) -> bool {
980 self.rules.is_empty()
981 }
982 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
984 self.rules.iter().filter(|r| r.conditional).collect()
985 }
986 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
988 self.rules.iter().filter(|r| !r.conditional).collect()
989 }
990 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
992 self.rules.iter().find(|r| r.name == name)
993 }
994}
995#[allow(dead_code)]
997pub struct FlatSubstitution {
998 pairs: Vec<(String, String)>,
999}
1000#[allow(dead_code)]
1001impl FlatSubstitution {
1002 pub fn new() -> Self {
1004 Self { pairs: Vec::new() }
1005 }
1006 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
1008 self.pairs.push((from.into(), to.into()));
1009 }
1010 pub fn apply(&self, s: &str) -> String {
1012 let mut result = s.to_string();
1013 for (from, to) in &self.pairs {
1014 result = result.replace(from.as_str(), to.as_str());
1015 }
1016 result
1017 }
1018 pub fn len(&self) -> usize {
1020 self.pairs.len()
1021 }
1022 pub fn is_empty(&self) -> bool {
1024 self.pairs.is_empty()
1025 }
1026}
1027#[allow(dead_code)]
1029#[derive(Debug, Clone, PartialEq, Eq)]
1030pub enum BuiltinKind {
1031 Type,
1033 Constructor,
1035 Recursor,
1037 Axiom,
1039 ArithOp,
1041 CmpOp,
1043 StringOp,
1045 TypeClass,
1047 Unknown,
1049}
1050impl BuiltinKind {
1051 #[allow(dead_code)]
1053 pub fn description(&self) -> &'static str {
1054 match self {
1055 BuiltinKind::Type => "primitive type",
1056 BuiltinKind::Constructor => "type constructor",
1057 BuiltinKind::Recursor => "recursor/eliminator",
1058 BuiltinKind::Axiom => "logical axiom",
1059 BuiltinKind::ArithOp => "arithmetic operation",
1060 BuiltinKind::CmpOp => "comparison operation",
1061 BuiltinKind::StringOp => "string operation",
1062 BuiltinKind::TypeClass => "type class",
1063 BuiltinKind::Unknown => "not a builtin",
1064 }
1065 }
1066}
1067#[allow(dead_code)]
1069pub struct WriteOnce<T> {
1070 value: std::cell::Cell<Option<T>>,
1071}
1072#[allow(dead_code)]
1073impl<T: Copy> WriteOnce<T> {
1074 pub fn new() -> Self {
1076 Self {
1077 value: std::cell::Cell::new(None),
1078 }
1079 }
1080 pub fn write(&self, val: T) -> bool {
1082 if self.value.get().is_some() {
1083 return false;
1084 }
1085 self.value.set(Some(val));
1086 true
1087 }
1088 pub fn read(&self) -> Option<T> {
1090 self.value.get()
1091 }
1092 pub fn is_written(&self) -> bool {
1094 self.value.get().is_some()
1095 }
1096}