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: std::time::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: std::time::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 = std::time::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 pub fn add(&mut self) {
120 let b = self
121 .stack
122 .pop()
123 .expect("stack must have at least two values for add");
124 let a = self
125 .stack
126 .pop()
127 .expect("stack must have at least two values for add");
128 self.stack.push(a + b);
129 }
130 pub fn sub(&mut self) {
132 let b = self
133 .stack
134 .pop()
135 .expect("stack must have at least two values for sub");
136 let a = self
137 .stack
138 .pop()
139 .expect("stack must have at least two values for sub");
140 self.stack.push(a - b);
141 }
142 pub fn mul(&mut self) {
144 let b = self
145 .stack
146 .pop()
147 .expect("stack must have at least two values for mul");
148 let a = self
149 .stack
150 .pop()
151 .expect("stack must have at least two values for mul");
152 self.stack.push(a * b);
153 }
154 pub fn peek(&self) -> Option<i64> {
156 self.stack.last().copied()
157 }
158 pub fn depth(&self) -> usize {
160 self.stack.len()
161 }
162}
163#[allow(dead_code)]
165pub enum Either2<A, B> {
166 First(A),
168 Second(B),
170}
171#[allow(dead_code)]
172impl<A, B> Either2<A, B> {
173 pub fn is_first(&self) -> bool {
175 matches!(self, Either2::First(_))
176 }
177 pub fn is_second(&self) -> bool {
179 matches!(self, Either2::Second(_))
180 }
181 pub fn first(self) -> Option<A> {
183 match self {
184 Either2::First(a) => Some(a),
185 _ => None,
186 }
187 }
188 pub fn second(self) -> Option<B> {
190 match self {
191 Either2::Second(b) => Some(b),
192 _ => None,
193 }
194 }
195 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
197 match self {
198 Either2::First(a) => Either2::First(f(a)),
199 Either2::Second(b) => Either2::Second(b),
200 }
201 }
202}
203#[allow(dead_code)]
205pub struct RawFnPtr {
206 ptr: usize,
208 arity: usize,
209 name: String,
210}
211#[allow(dead_code)]
212impl RawFnPtr {
213 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
215 Self {
216 ptr,
217 arity,
218 name: name.into(),
219 }
220 }
221 pub fn arity(&self) -> usize {
223 self.arity
224 }
225 pub fn name(&self) -> &str {
227 &self.name
228 }
229 pub fn raw(&self) -> usize {
231 self.ptr
232 }
233}
234#[allow(dead_code)]
236pub struct PathBuf {
237 components: Vec<String>,
238}
239#[allow(dead_code)]
240impl PathBuf {
241 pub fn new() -> Self {
243 Self {
244 components: Vec::new(),
245 }
246 }
247 pub fn push(&mut self, comp: impl Into<String>) {
249 self.components.push(comp.into());
250 }
251 pub fn pop(&mut self) {
253 self.components.pop();
254 }
255 pub fn as_str(&self) -> String {
257 self.components.join("/")
258 }
259 pub fn depth(&self) -> usize {
261 self.components.len()
262 }
263 pub fn clear(&mut self) {
265 self.components.clear();
266 }
267}
268#[allow(dead_code)]
270pub struct StringPool {
271 free: Vec<String>,
272}
273#[allow(dead_code)]
274impl StringPool {
275 pub fn new() -> Self {
277 Self { free: Vec::new() }
278 }
279 pub fn take(&mut self) -> String {
281 self.free.pop().unwrap_or_default()
282 }
283 pub fn give(&mut self, mut s: String) {
285 s.clear();
286 self.free.push(s);
287 }
288 pub fn free_count(&self) -> usize {
290 self.free.len()
291 }
292}
293#[allow(dead_code)]
295pub struct Stopwatch {
296 start: std::time::Instant,
297 splits: Vec<f64>,
298}
299#[allow(dead_code)]
300impl Stopwatch {
301 pub fn start() -> Self {
303 Self {
304 start: std::time::Instant::now(),
305 splits: Vec::new(),
306 }
307 }
308 pub fn split(&mut self) {
310 self.splits.push(self.elapsed_ms());
311 }
312 pub fn elapsed_ms(&self) -> f64 {
314 self.start.elapsed().as_secs_f64() * 1000.0
315 }
316 pub fn splits(&self) -> &[f64] {
318 &self.splits
319 }
320 pub fn num_splits(&self) -> usize {
322 self.splits.len()
323 }
324}
325#[allow(dead_code)]
327pub struct TransitiveClosure {
328 adj: Vec<Vec<usize>>,
329 n: usize,
330}
331#[allow(dead_code)]
332impl TransitiveClosure {
333 pub fn new(n: usize) -> Self {
335 Self {
336 adj: vec![Vec::new(); n],
337 n,
338 }
339 }
340 pub fn add_edge(&mut self, from: usize, to: usize) {
342 if from < self.n {
343 self.adj[from].push(to);
344 }
345 }
346 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
348 let mut visited = vec![false; self.n];
349 let mut queue = std::collections::VecDeque::new();
350 queue.push_back(start);
351 while let Some(node) = queue.pop_front() {
352 if node >= self.n || visited[node] {
353 continue;
354 }
355 visited[node] = true;
356 for &next in &self.adj[node] {
357 queue.push_back(next);
358 }
359 }
360 (0..self.n).filter(|&i| visited[i]).collect()
361 }
362 pub fn can_reach(&self, from: usize, to: usize) -> bool {
364 self.reachable_from(from).contains(&to)
365 }
366}
367#[allow(dead_code)]
369#[derive(Debug, Clone)]
370pub struct BuiltinInfo {
371 pub name: &'static str,
373 pub kind: BuiltinKind,
375 pub description: &'static str,
377}
378#[allow(dead_code)]
380#[allow(missing_docs)]
381pub struct RewriteRule {
382 pub name: String,
384 pub lhs: String,
386 pub rhs: String,
388 pub conditional: bool,
390}
391#[allow(dead_code)]
392impl RewriteRule {
393 pub fn unconditional(
395 name: impl Into<String>,
396 lhs: impl Into<String>,
397 rhs: impl Into<String>,
398 ) -> Self {
399 Self {
400 name: name.into(),
401 lhs: lhs.into(),
402 rhs: rhs.into(),
403 conditional: false,
404 }
405 }
406 pub fn conditional(
408 name: impl Into<String>,
409 lhs: impl Into<String>,
410 rhs: impl Into<String>,
411 ) -> Self {
412 Self {
413 name: name.into(),
414 lhs: lhs.into(),
415 rhs: rhs.into(),
416 conditional: true,
417 }
418 }
419 pub fn display(&self) -> String {
421 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
422 }
423}
424#[allow(dead_code)]
426pub struct SlidingSum {
427 window: Vec<f64>,
428 capacity: usize,
429 pos: usize,
430 sum: f64,
431 count: usize,
432}
433#[allow(dead_code)]
434impl SlidingSum {
435 pub fn new(capacity: usize) -> Self {
437 Self {
438 window: vec![0.0; capacity],
439 capacity,
440 pos: 0,
441 sum: 0.0,
442 count: 0,
443 }
444 }
445 pub fn push(&mut self, val: f64) {
447 let oldest = self.window[self.pos];
448 self.sum -= oldest;
449 self.sum += val;
450 self.window[self.pos] = val;
451 self.pos = (self.pos + 1) % self.capacity;
452 if self.count < self.capacity {
453 self.count += 1;
454 }
455 }
456 pub fn sum(&self) -> f64 {
458 self.sum
459 }
460 pub fn mean(&self) -> Option<f64> {
462 if self.count == 0 {
463 None
464 } else {
465 Some(self.sum / self.count as f64)
466 }
467 }
468 pub fn count(&self) -> usize {
470 self.count
471 }
472}
473#[allow(dead_code)]
475pub struct SparseVec<T: Default + Clone + PartialEq> {
476 entries: std::collections::HashMap<usize, T>,
477 default_: T,
478 logical_len: usize,
479}
480#[allow(dead_code)]
481impl<T: Default + Clone + PartialEq> SparseVec<T> {
482 pub fn new(len: usize) -> Self {
484 Self {
485 entries: std::collections::HashMap::new(),
486 default_: T::default(),
487 logical_len: len,
488 }
489 }
490 pub fn set(&mut self, idx: usize, val: T) {
492 if val == self.default_ {
493 self.entries.remove(&idx);
494 } else {
495 self.entries.insert(idx, val);
496 }
497 }
498 pub fn get(&self, idx: usize) -> &T {
500 self.entries.get(&idx).unwrap_or(&self.default_)
501 }
502 pub fn len(&self) -> usize {
504 self.logical_len
505 }
506 pub fn is_empty(&self) -> bool {
508 self.len() == 0
509 }
510 pub fn nnz(&self) -> usize {
512 self.entries.len()
513 }
514}
515#[allow(dead_code)]
517pub struct SmallMap<K: Ord + Clone, V: Clone> {
518 entries: Vec<(K, V)>,
519}
520#[allow(dead_code)]
521impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
522 pub fn new() -> Self {
524 Self {
525 entries: Vec::new(),
526 }
527 }
528 pub fn insert(&mut self, key: K, val: V) {
530 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
531 Ok(i) => self.entries[i].1 = val,
532 Err(i) => self.entries.insert(i, (key, val)),
533 }
534 }
535 pub fn get(&self, key: &K) -> Option<&V> {
537 self.entries
538 .binary_search_by_key(&key, |(k, _)| k)
539 .ok()
540 .map(|i| &self.entries[i].1)
541 }
542 pub fn len(&self) -> usize {
544 self.entries.len()
545 }
546 pub fn is_empty(&self) -> bool {
548 self.entries.is_empty()
549 }
550 pub fn keys(&self) -> Vec<&K> {
552 self.entries.iter().map(|(k, _)| k).collect()
553 }
554 pub fn values(&self) -> Vec<&V> {
556 self.entries.iter().map(|(_, v)| v).collect()
557 }
558}
559#[allow(dead_code)]
561pub struct StatSummary {
562 count: u64,
563 sum: f64,
564 min: f64,
565 max: f64,
566}
567#[allow(dead_code)]
568impl StatSummary {
569 pub fn new() -> Self {
571 Self {
572 count: 0,
573 sum: 0.0,
574 min: f64::INFINITY,
575 max: f64::NEG_INFINITY,
576 }
577 }
578 pub fn record(&mut self, val: f64) {
580 self.count += 1;
581 self.sum += val;
582 if val < self.min {
583 self.min = val;
584 }
585 if val > self.max {
586 self.max = val;
587 }
588 }
589 pub fn mean(&self) -> Option<f64> {
591 if self.count == 0 {
592 None
593 } else {
594 Some(self.sum / self.count as f64)
595 }
596 }
597 pub fn min(&self) -> Option<f64> {
599 if self.count == 0 {
600 None
601 } else {
602 Some(self.min)
603 }
604 }
605 pub fn max(&self) -> Option<f64> {
607 if self.count == 0 {
608 None
609 } else {
610 Some(self.max)
611 }
612 }
613 pub fn count(&self) -> u64 {
615 self.count
616 }
617}
618#[allow(dead_code)]
620pub struct SimpleDag {
621 edges: Vec<Vec<usize>>,
623}
624#[allow(dead_code)]
625impl SimpleDag {
626 pub fn new(n: usize) -> Self {
628 Self {
629 edges: vec![Vec::new(); n],
630 }
631 }
632 pub fn add_edge(&mut self, from: usize, to: usize) {
634 if from < self.edges.len() {
635 self.edges[from].push(to);
636 }
637 }
638 pub fn successors(&self, node: usize) -> &[usize] {
640 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
641 }
642 pub fn can_reach(&self, from: usize, to: usize) -> bool {
644 let mut visited = vec![false; self.edges.len()];
645 self.dfs(from, to, &mut visited)
646 }
647 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
648 if cur == target {
649 return true;
650 }
651 if cur >= visited.len() || visited[cur] {
652 return false;
653 }
654 visited[cur] = true;
655 for &next in self.successors(cur) {
656 if self.dfs(next, target, visited) {
657 return true;
658 }
659 }
660 false
661 }
662 pub fn topological_sort(&self) -> Option<Vec<usize>> {
664 let n = self.edges.len();
665 let mut in_degree = vec![0usize; n];
666 for succs in &self.edges {
667 for &s in succs {
668 if s < n {
669 in_degree[s] += 1;
670 }
671 }
672 }
673 let mut queue: std::collections::VecDeque<usize> =
674 (0..n).filter(|&i| in_degree[i] == 0).collect();
675 let mut order = Vec::new();
676 while let Some(node) = queue.pop_front() {
677 order.push(node);
678 for &s in self.successors(node) {
679 if s < n {
680 in_degree[s] -= 1;
681 if in_degree[s] == 0 {
682 queue.push_back(s);
683 }
684 }
685 }
686 }
687 if order.len() == n {
688 Some(order)
689 } else {
690 None
691 }
692 }
693 pub fn num_nodes(&self) -> usize {
695 self.edges.len()
696 }
697}
698#[allow(dead_code)]
700pub struct ConfigNode {
701 key: String,
702 value: Option<String>,
703 children: Vec<ConfigNode>,
704}
705#[allow(dead_code)]
706impl ConfigNode {
707 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
709 Self {
710 key: key.into(),
711 value: Some(value.into()),
712 children: Vec::new(),
713 }
714 }
715 pub fn section(key: impl Into<String>) -> Self {
717 Self {
718 key: key.into(),
719 value: None,
720 children: Vec::new(),
721 }
722 }
723 pub fn add_child(&mut self, child: ConfigNode) {
725 self.children.push(child);
726 }
727 pub fn key(&self) -> &str {
729 &self.key
730 }
731 pub fn value(&self) -> Option<&str> {
733 self.value.as_deref()
734 }
735 pub fn num_children(&self) -> usize {
737 self.children.len()
738 }
739 pub fn lookup(&self, path: &str) -> Option<&str> {
741 let mut parts = path.splitn(2, '.');
742 let head = parts.next()?;
743 let tail = parts.next();
744 if head != self.key {
745 return None;
746 }
747 match tail {
748 None => self.value.as_deref(),
749 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
750 }
751 }
752 fn lookup_relative(&self, path: &str) -> Option<&str> {
753 let mut parts = path.splitn(2, '.');
754 let head = parts.next()?;
755 let tail = parts.next();
756 if head != self.key {
757 return None;
758 }
759 match tail {
760 None => self.value.as_deref(),
761 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
762 }
763 }
764}
765#[allow(dead_code)]
767pub struct VersionedRecord<T: Clone> {
768 history: Vec<T>,
769}
770#[allow(dead_code)]
771impl<T: Clone> VersionedRecord<T> {
772 pub fn new(initial: T) -> Self {
774 Self {
775 history: vec![initial],
776 }
777 }
778 pub fn update(&mut self, val: T) {
780 self.history.push(val);
781 }
782 pub fn current(&self) -> &T {
784 self.history
785 .last()
786 .expect("VersionedRecord history is always non-empty after construction")
787 }
788 pub fn at_version(&self, n: usize) -> Option<&T> {
790 self.history.get(n)
791 }
792 pub fn version(&self) -> usize {
794 self.history.len() - 1
795 }
796 pub fn has_history(&self) -> bool {
798 self.history.len() > 1
799 }
800}
801#[allow(dead_code)]
803pub struct LabelSet {
804 labels: Vec<String>,
805}
806#[allow(dead_code)]
807impl LabelSet {
808 pub fn new() -> Self {
810 Self { labels: Vec::new() }
811 }
812 pub fn add(&mut self, label: impl Into<String>) {
814 let s = label.into();
815 if !self.labels.contains(&s) {
816 self.labels.push(s);
817 }
818 }
819 pub fn has(&self, label: &str) -> bool {
821 self.labels.iter().any(|l| l == label)
822 }
823 pub fn count(&self) -> usize {
825 self.labels.len()
826 }
827 pub fn all(&self) -> &[String] {
829 &self.labels
830 }
831}
832#[allow(dead_code)]
834pub struct TransformStat {
835 before: StatSummary,
836 after: StatSummary,
837}
838#[allow(dead_code)]
839impl TransformStat {
840 pub fn new() -> Self {
842 Self {
843 before: StatSummary::new(),
844 after: StatSummary::new(),
845 }
846 }
847 pub fn record_before(&mut self, v: f64) {
849 self.before.record(v);
850 }
851 pub fn record_after(&mut self, v: f64) {
853 self.after.record(v);
854 }
855 pub fn mean_ratio(&self) -> Option<f64> {
857 let b = self.before.mean()?;
858 let a = self.after.mean()?;
859 if b.abs() < f64::EPSILON {
860 return None;
861 }
862 Some(a / b)
863 }
864}
865#[allow(dead_code)]
867pub struct FocusStack<T> {
868 items: Vec<T>,
869}
870#[allow(dead_code)]
871impl<T> FocusStack<T> {
872 pub fn new() -> Self {
874 Self { items: Vec::new() }
875 }
876 pub fn focus(&mut self, item: T) {
878 self.items.push(item);
879 }
880 pub fn blur(&mut self) -> Option<T> {
882 self.items.pop()
883 }
884 pub fn current(&self) -> Option<&T> {
886 self.items.last()
887 }
888 pub fn depth(&self) -> usize {
890 self.items.len()
891 }
892 pub fn is_empty(&self) -> bool {
894 self.items.is_empty()
895 }
896}
897#[allow(dead_code)]
899pub struct WindowIterator<'a, T> {
900 pub(super) data: &'a [T],
901 pub(super) pos: usize,
902 pub(super) window: usize,
903}
904#[allow(dead_code)]
905impl<'a, T> WindowIterator<'a, T> {
906 pub fn new(data: &'a [T], window: usize) -> Self {
908 Self {
909 data,
910 pos: 0,
911 window,
912 }
913 }
914}
915#[allow(dead_code)]
917pub struct NonEmptyVec<T> {
918 head: T,
919 tail: Vec<T>,
920}
921#[allow(dead_code)]
922impl<T> NonEmptyVec<T> {
923 pub fn singleton(val: T) -> Self {
925 Self {
926 head: val,
927 tail: Vec::new(),
928 }
929 }
930 pub fn push(&mut self, val: T) {
932 self.tail.push(val);
933 }
934 pub fn first(&self) -> &T {
936 &self.head
937 }
938 pub fn last(&self) -> &T {
940 self.tail.last().unwrap_or(&self.head)
941 }
942 pub fn len(&self) -> usize {
944 1 + self.tail.len()
945 }
946 pub fn is_empty(&self) -> bool {
948 self.len() == 0
949 }
950 pub fn to_vec(&self) -> Vec<&T> {
952 let mut v = vec![&self.head];
953 v.extend(self.tail.iter());
954 v
955 }
956}
957#[allow(dead_code)]
959pub struct RewriteRuleSet {
960 rules: Vec<RewriteRule>,
961}
962#[allow(dead_code)]
963impl RewriteRuleSet {
964 pub fn new() -> Self {
966 Self { rules: Vec::new() }
967 }
968 pub fn add(&mut self, rule: RewriteRule) {
970 self.rules.push(rule);
971 }
972 pub fn len(&self) -> usize {
974 self.rules.len()
975 }
976 pub fn is_empty(&self) -> bool {
978 self.rules.is_empty()
979 }
980 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
982 self.rules.iter().filter(|r| r.conditional).collect()
983 }
984 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
986 self.rules.iter().filter(|r| !r.conditional).collect()
987 }
988 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
990 self.rules.iter().find(|r| r.name == name)
991 }
992}
993#[allow(dead_code)]
995pub struct FlatSubstitution {
996 pairs: Vec<(String, String)>,
997}
998#[allow(dead_code)]
999impl FlatSubstitution {
1000 pub fn new() -> Self {
1002 Self { pairs: Vec::new() }
1003 }
1004 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
1006 self.pairs.push((from.into(), to.into()));
1007 }
1008 pub fn apply(&self, s: &str) -> String {
1010 let mut result = s.to_string();
1011 for (from, to) in &self.pairs {
1012 result = result.replace(from.as_str(), to.as_str());
1013 }
1014 result
1015 }
1016 pub fn len(&self) -> usize {
1018 self.pairs.len()
1019 }
1020 pub fn is_empty(&self) -> bool {
1022 self.pairs.is_empty()
1023 }
1024}
1025#[allow(dead_code)]
1027#[derive(Debug, Clone, PartialEq, Eq)]
1028pub enum BuiltinKind {
1029 Type,
1031 Constructor,
1033 Recursor,
1035 Axiom,
1037 ArithOp,
1039 CmpOp,
1041 StringOp,
1043 TypeClass,
1045 Unknown,
1047}
1048impl BuiltinKind {
1049 #[allow(dead_code)]
1051 pub fn description(&self) -> &'static str {
1052 match self {
1053 BuiltinKind::Type => "primitive type",
1054 BuiltinKind::Constructor => "type constructor",
1055 BuiltinKind::Recursor => "recursor/eliminator",
1056 BuiltinKind::Axiom => "logical axiom",
1057 BuiltinKind::ArithOp => "arithmetic operation",
1058 BuiltinKind::CmpOp => "comparison operation",
1059 BuiltinKind::StringOp => "string operation",
1060 BuiltinKind::TypeClass => "type class",
1061 BuiltinKind::Unknown => "not a builtin",
1062 }
1063 }
1064}
1065#[allow(dead_code)]
1067pub struct WriteOnce<T> {
1068 value: std::cell::Cell<Option<T>>,
1069}
1070#[allow(dead_code)]
1071impl<T: Copy> WriteOnce<T> {
1072 pub fn new() -> Self {
1074 Self {
1075 value: std::cell::Cell::new(None),
1076 }
1077 }
1078 pub fn write(&self, val: T) -> bool {
1080 if self.value.get().is_some() {
1081 return false;
1082 }
1083 self.value.set(Some(val));
1084 true
1085 }
1086 pub fn read(&self) -> Option<T> {
1088 self.value.get()
1089 }
1090 pub fn is_written(&self) -> bool {
1092 self.value.get().is_some()
1093 }
1094}