1use std::collections::HashMap;
6
7#[allow(dead_code)]
9pub struct ConfigNode {
10 key: String,
11 value: Option<String>,
12 children: Vec<ConfigNode>,
13}
14#[allow(dead_code)]
15impl ConfigNode {
16 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
18 Self {
19 key: key.into(),
20 value: Some(value.into()),
21 children: Vec::new(),
22 }
23 }
24 pub fn section(key: impl Into<String>) -> Self {
26 Self {
27 key: key.into(),
28 value: None,
29 children: Vec::new(),
30 }
31 }
32 pub fn add_child(&mut self, child: ConfigNode) {
34 self.children.push(child);
35 }
36 pub fn key(&self) -> &str {
38 &self.key
39 }
40 pub fn value(&self) -> Option<&str> {
42 self.value.as_deref()
43 }
44 pub fn num_children(&self) -> usize {
46 self.children.len()
47 }
48 pub fn lookup(&self, path: &str) -> Option<&str> {
50 let mut parts = path.splitn(2, '.');
51 let head = parts.next()?;
52 let tail = parts.next();
53 if head != self.key {
54 return None;
55 }
56 match tail {
57 None => self.value.as_deref(),
58 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
59 }
60 }
61 fn lookup_relative(&self, path: &str) -> Option<&str> {
62 let mut parts = path.splitn(2, '.');
63 let head = parts.next()?;
64 let tail = parts.next();
65 if head != self.key {
66 return None;
67 }
68 match tail {
69 None => self.value.as_deref(),
70 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
71 }
72 }
73}
74#[allow(dead_code)]
76pub struct TokenBucket {
77 capacity: u64,
78 tokens: u64,
79 refill_per_ms: u64,
80 last_refill: std::time::Instant,
81}
82#[allow(dead_code)]
83impl TokenBucket {
84 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
86 Self {
87 capacity,
88 tokens: capacity,
89 refill_per_ms,
90 last_refill: std::time::Instant::now(),
91 }
92 }
93 pub fn try_consume(&mut self, n: u64) -> bool {
95 self.refill();
96 if self.tokens >= n {
97 self.tokens -= n;
98 true
99 } else {
100 false
101 }
102 }
103 fn refill(&mut self) {
104 let now = std::time::Instant::now();
105 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
106 if elapsed_ms > 0 {
107 let new_tokens = elapsed_ms * self.refill_per_ms;
108 self.tokens = (self.tokens + new_tokens).min(self.capacity);
109 self.last_refill = now;
110 }
111 }
112 pub fn available(&self) -> u64 {
114 self.tokens
115 }
116 pub fn capacity(&self) -> u64 {
118 self.capacity
119 }
120}
121#[allow(dead_code)]
123#[allow(missing_docs)]
124pub struct RewriteRule {
125 pub name: String,
127 pub lhs: String,
129 pub rhs: String,
131 pub conditional: bool,
133}
134#[allow(dead_code)]
135impl RewriteRule {
136 pub fn unconditional(
138 name: impl Into<String>,
139 lhs: impl Into<String>,
140 rhs: impl Into<String>,
141 ) -> Self {
142 Self {
143 name: name.into(),
144 lhs: lhs.into(),
145 rhs: rhs.into(),
146 conditional: false,
147 }
148 }
149 pub fn conditional(
151 name: impl Into<String>,
152 lhs: impl Into<String>,
153 rhs: impl Into<String>,
154 ) -> Self {
155 Self {
156 name: name.into(),
157 lhs: lhs.into(),
158 rhs: rhs.into(),
159 conditional: true,
160 }
161 }
162 pub fn display(&self) -> String {
164 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
165 }
166}
167#[allow(dead_code)]
169pub struct NonEmptyVec<T> {
170 head: T,
171 tail: Vec<T>,
172}
173#[allow(dead_code)]
174impl<T> NonEmptyVec<T> {
175 pub fn singleton(val: T) -> Self {
177 Self {
178 head: val,
179 tail: Vec::new(),
180 }
181 }
182 pub fn push(&mut self, val: T) {
184 self.tail.push(val);
185 }
186 pub fn first(&self) -> &T {
188 &self.head
189 }
190 pub fn last(&self) -> &T {
192 self.tail.last().unwrap_or(&self.head)
193 }
194 pub fn len(&self) -> usize {
196 1 + self.tail.len()
197 }
198 pub fn is_empty(&self) -> bool {
200 self.len() == 0
201 }
202 pub fn to_vec(&self) -> Vec<&T> {
204 let mut v = vec![&self.head];
205 v.extend(self.tail.iter());
206 v
207 }
208}
209#[allow(dead_code)]
211pub struct TransformStat {
212 before: StatSummary,
213 after: StatSummary,
214}
215#[allow(dead_code)]
216impl TransformStat {
217 pub fn new() -> Self {
219 Self {
220 before: StatSummary::new(),
221 after: StatSummary::new(),
222 }
223 }
224 pub fn record_before(&mut self, v: f64) {
226 self.before.record(v);
227 }
228 pub fn record_after(&mut self, v: f64) {
230 self.after.record(v);
231 }
232 pub fn mean_ratio(&self) -> Option<f64> {
234 let b = self.before.mean()?;
235 let a = self.after.mean()?;
236 if b.abs() < f64::EPSILON {
237 return None;
238 }
239 Some(a / b)
240 }
241}
242#[allow(dead_code)]
244pub struct SmallMap<K: Ord + Clone, V: Clone> {
245 entries: Vec<(K, V)>,
246}
247#[allow(dead_code)]
248impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
249 pub fn new() -> Self {
251 Self {
252 entries: Vec::new(),
253 }
254 }
255 pub fn insert(&mut self, key: K, val: V) {
257 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
258 Ok(i) => self.entries[i].1 = val,
259 Err(i) => self.entries.insert(i, (key, val)),
260 }
261 }
262 pub fn get(&self, key: &K) -> Option<&V> {
264 self.entries
265 .binary_search_by_key(&key, |(k, _)| k)
266 .ok()
267 .map(|i| &self.entries[i].1)
268 }
269 pub fn len(&self) -> usize {
271 self.entries.len()
272 }
273 pub fn is_empty(&self) -> bool {
275 self.entries.is_empty()
276 }
277 pub fn keys(&self) -> Vec<&K> {
279 self.entries.iter().map(|(k, _)| k).collect()
280 }
281 pub fn values(&self) -> Vec<&V> {
283 self.entries.iter().map(|(_, v)| v).collect()
284 }
285}
286#[allow(dead_code)]
288pub struct TransitiveClosure {
289 adj: Vec<Vec<usize>>,
290 n: usize,
291}
292#[allow(dead_code)]
293impl TransitiveClosure {
294 pub fn new(n: usize) -> Self {
296 Self {
297 adj: vec![Vec::new(); n],
298 n,
299 }
300 }
301 pub fn add_edge(&mut self, from: usize, to: usize) {
303 if from < self.n {
304 self.adj[from].push(to);
305 }
306 }
307 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
309 let mut visited = vec![false; self.n];
310 let mut queue = std::collections::VecDeque::new();
311 queue.push_back(start);
312 while let Some(node) = queue.pop_front() {
313 if node >= self.n || visited[node] {
314 continue;
315 }
316 visited[node] = true;
317 for &next in &self.adj[node] {
318 queue.push_back(next);
319 }
320 }
321 (0..self.n).filter(|&i| visited[i]).collect()
322 }
323 pub fn can_reach(&self, from: usize, to: usize) -> bool {
325 self.reachable_from(from).contains(&to)
326 }
327}
328#[derive(Clone, Debug, Default)]
330pub struct BetaStats {
331 pub total_reductions: u64,
333 pub max_depth: u32,
335 pub fuel_exhaustions: u64,
337}
338impl BetaStats {
339 pub fn new() -> Self {
341 Self::default()
342 }
343 pub fn record_reduction(&mut self) {
345 self.total_reductions += 1;
346 }
347 pub fn record_fuel_exhaustion(&mut self) {
349 self.fuel_exhaustions += 1;
350 }
351 pub fn update_depth(&mut self, depth: u32) {
353 if depth > self.max_depth {
354 self.max_depth = depth;
355 }
356 }
357}
358#[allow(dead_code)]
360pub struct StatSummary {
361 count: u64,
362 sum: f64,
363 min: f64,
364 max: f64,
365}
366#[allow(dead_code)]
367impl StatSummary {
368 pub fn new() -> Self {
370 Self {
371 count: 0,
372 sum: 0.0,
373 min: f64::INFINITY,
374 max: f64::NEG_INFINITY,
375 }
376 }
377 pub fn record(&mut self, val: f64) {
379 self.count += 1;
380 self.sum += val;
381 if val < self.min {
382 self.min = val;
383 }
384 if val > self.max {
385 self.max = val;
386 }
387 }
388 pub fn mean(&self) -> Option<f64> {
390 if self.count == 0 {
391 None
392 } else {
393 Some(self.sum / self.count as f64)
394 }
395 }
396 pub fn min(&self) -> Option<f64> {
398 if self.count == 0 {
399 None
400 } else {
401 Some(self.min)
402 }
403 }
404 pub fn max(&self) -> Option<f64> {
406 if self.count == 0 {
407 None
408 } else {
409 Some(self.max)
410 }
411 }
412 pub fn count(&self) -> u64 {
414 self.count
415 }
416}
417#[allow(dead_code)]
419pub struct LabelSet {
420 labels: Vec<String>,
421}
422#[allow(dead_code)]
423impl LabelSet {
424 pub fn new() -> Self {
426 Self { labels: Vec::new() }
427 }
428 pub fn add(&mut self, label: impl Into<String>) {
430 let s = label.into();
431 if !self.labels.contains(&s) {
432 self.labels.push(s);
433 }
434 }
435 pub fn has(&self, label: &str) -> bool {
437 self.labels.iter().any(|l| l == label)
438 }
439 pub fn count(&self) -> usize {
441 self.labels.len()
442 }
443 pub fn all(&self) -> &[String] {
445 &self.labels
446 }
447}
448#[allow(dead_code)]
450pub struct SimpleDag {
451 edges: Vec<Vec<usize>>,
453}
454#[allow(dead_code)]
455impl SimpleDag {
456 pub fn new(n: usize) -> Self {
458 Self {
459 edges: vec![Vec::new(); n],
460 }
461 }
462 pub fn add_edge(&mut self, from: usize, to: usize) {
464 if from < self.edges.len() {
465 self.edges[from].push(to);
466 }
467 }
468 pub fn successors(&self, node: usize) -> &[usize] {
470 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
471 }
472 pub fn can_reach(&self, from: usize, to: usize) -> bool {
474 let mut visited = vec![false; self.edges.len()];
475 self.dfs(from, to, &mut visited)
476 }
477 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
478 if cur == target {
479 return true;
480 }
481 if cur >= visited.len() || visited[cur] {
482 return false;
483 }
484 visited[cur] = true;
485 for &next in self.successors(cur) {
486 if self.dfs(next, target, visited) {
487 return true;
488 }
489 }
490 false
491 }
492 pub fn topological_sort(&self) -> Option<Vec<usize>> {
494 let n = self.edges.len();
495 let mut in_degree = vec![0usize; n];
496 for succs in &self.edges {
497 for &s in succs {
498 if s < n {
499 in_degree[s] += 1;
500 }
501 }
502 }
503 let mut queue: std::collections::VecDeque<usize> =
504 (0..n).filter(|&i| in_degree[i] == 0).collect();
505 let mut order = Vec::new();
506 while let Some(node) = queue.pop_front() {
507 order.push(node);
508 for &s in self.successors(node) {
509 if s < n {
510 in_degree[s] -= 1;
511 if in_degree[s] == 0 {
512 queue.push_back(s);
513 }
514 }
515 }
516 }
517 if order.len() == n {
518 Some(order)
519 } else {
520 None
521 }
522 }
523 pub fn num_nodes(&self) -> usize {
525 self.edges.len()
526 }
527}
528#[allow(dead_code)]
530pub struct FocusStack<T> {
531 items: Vec<T>,
532}
533#[allow(dead_code)]
534impl<T> FocusStack<T> {
535 pub fn new() -> Self {
537 Self { items: Vec::new() }
538 }
539 pub fn focus(&mut self, item: T) {
541 self.items.push(item);
542 }
543 pub fn blur(&mut self) -> Option<T> {
545 self.items.pop()
546 }
547 pub fn current(&self) -> Option<&T> {
549 self.items.last()
550 }
551 pub fn depth(&self) -> usize {
553 self.items.len()
554 }
555 pub fn is_empty(&self) -> bool {
557 self.items.is_empty()
558 }
559}
560#[allow(dead_code)]
562pub struct SlidingSum {
563 window: Vec<f64>,
564 capacity: usize,
565 pos: usize,
566 sum: f64,
567 count: usize,
568}
569#[allow(dead_code)]
570impl SlidingSum {
571 pub fn new(capacity: usize) -> Self {
573 Self {
574 window: vec![0.0; capacity],
575 capacity,
576 pos: 0,
577 sum: 0.0,
578 count: 0,
579 }
580 }
581 pub fn push(&mut self, val: f64) {
583 let oldest = self.window[self.pos];
584 self.sum -= oldest;
585 self.sum += val;
586 self.window[self.pos] = val;
587 self.pos = (self.pos + 1) % self.capacity;
588 if self.count < self.capacity {
589 self.count += 1;
590 }
591 }
592 pub fn sum(&self) -> f64 {
594 self.sum
595 }
596 pub fn mean(&self) -> Option<f64> {
598 if self.count == 0 {
599 None
600 } else {
601 Some(self.sum / self.count as f64)
602 }
603 }
604 pub fn count(&self) -> usize {
606 self.count
607 }
608}
609#[allow(dead_code)]
611pub struct RawFnPtr {
612 ptr: usize,
614 arity: usize,
615 name: String,
616}
617#[allow(dead_code)]
618impl RawFnPtr {
619 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
621 Self {
622 ptr,
623 arity,
624 name: name.into(),
625 }
626 }
627 pub fn arity(&self) -> usize {
629 self.arity
630 }
631 pub fn name(&self) -> &str {
633 &self.name
634 }
635 pub fn raw(&self) -> usize {
637 self.ptr
638 }
639}
640#[allow(dead_code)]
642pub struct StringPool {
643 free: Vec<String>,
644}
645#[allow(dead_code)]
646impl StringPool {
647 pub fn new() -> Self {
649 Self { free: Vec::new() }
650 }
651 pub fn take(&mut self) -> String {
653 self.free.pop().unwrap_or_default()
654 }
655 pub fn give(&mut self, mut s: String) {
657 s.clear();
658 self.free.push(s);
659 }
660 pub fn free_count(&self) -> usize {
662 self.free.len()
663 }
664}
665#[allow(dead_code)]
667#[allow(missing_docs)]
668pub enum DecisionNode {
669 Leaf(String),
671 Branch {
673 key: String,
674 val: String,
675 yes_branch: Box<DecisionNode>,
676 no_branch: Box<DecisionNode>,
677 },
678}
679#[allow(dead_code)]
680impl DecisionNode {
681 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
683 match self {
684 DecisionNode::Leaf(action) => action.as_str(),
685 DecisionNode::Branch {
686 key,
687 val,
688 yes_branch,
689 no_branch,
690 } => {
691 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
692 if actual == val.as_str() {
693 yes_branch.evaluate(ctx)
694 } else {
695 no_branch.evaluate(ctx)
696 }
697 }
698 }
699 }
700 pub fn depth(&self) -> usize {
702 match self {
703 DecisionNode::Leaf(_) => 0,
704 DecisionNode::Branch {
705 yes_branch,
706 no_branch,
707 ..
708 } => 1 + yes_branch.depth().max(no_branch.depth()),
709 }
710 }
711}
712#[allow(dead_code)]
714pub enum Either2<A, B> {
715 First(A),
717 Second(B),
719}
720#[allow(dead_code)]
721impl<A, B> Either2<A, B> {
722 pub fn is_first(&self) -> bool {
724 matches!(self, Either2::First(_))
725 }
726 pub fn is_second(&self) -> bool {
728 matches!(self, Either2::Second(_))
729 }
730 pub fn first(self) -> Option<A> {
732 match self {
733 Either2::First(a) => Some(a),
734 _ => None,
735 }
736 }
737 pub fn second(self) -> Option<B> {
739 match self {
740 Either2::Second(b) => Some(b),
741 _ => None,
742 }
743 }
744 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
746 match self {
747 Either2::First(a) => Either2::First(f(a)),
748 Either2::Second(b) => Either2::Second(b),
749 }
750 }
751}
752#[allow(dead_code)]
754pub struct WindowIterator<'a, T> {
755 pub(super) data: &'a [T],
756 pub(super) pos: usize,
757 pub(super) window: usize,
758}
759#[allow(dead_code)]
760impl<'a, T> WindowIterator<'a, T> {
761 pub fn new(data: &'a [T], window: usize) -> Self {
763 Self {
764 data,
765 pos: 0,
766 window,
767 }
768 }
769}
770#[allow(dead_code)]
772pub struct WriteOnce<T> {
773 value: std::cell::Cell<Option<T>>,
774}
775#[allow(dead_code)]
776impl<T: Copy> WriteOnce<T> {
777 pub fn new() -> Self {
779 Self {
780 value: std::cell::Cell::new(None),
781 }
782 }
783 pub fn write(&self, val: T) -> bool {
785 if self.value.get().is_some() {
786 return false;
787 }
788 self.value.set(Some(val));
789 true
790 }
791 pub fn read(&self) -> Option<T> {
793 self.value.get()
794 }
795 pub fn is_written(&self) -> bool {
797 self.value.get().is_some()
798 }
799}
800#[allow(dead_code)]
802pub struct PathBuf {
803 components: Vec<String>,
804}
805#[allow(dead_code)]
806impl PathBuf {
807 pub fn new() -> Self {
809 Self {
810 components: Vec::new(),
811 }
812 }
813 pub fn push(&mut self, comp: impl Into<String>) {
815 self.components.push(comp.into());
816 }
817 pub fn pop(&mut self) {
819 self.components.pop();
820 }
821 pub fn as_str(&self) -> String {
823 self.components.join("/")
824 }
825 pub fn depth(&self) -> usize {
827 self.components.len()
828 }
829 pub fn clear(&mut self) {
831 self.components.clear();
832 }
833}
834#[allow(dead_code)]
836pub struct Stopwatch {
837 start: std::time::Instant,
838 splits: Vec<f64>,
839}
840#[allow(dead_code)]
841impl Stopwatch {
842 pub fn start() -> Self {
844 Self {
845 start: std::time::Instant::now(),
846 splits: Vec::new(),
847 }
848 }
849 pub fn split(&mut self) {
851 self.splits.push(self.elapsed_ms());
852 }
853 pub fn elapsed_ms(&self) -> f64 {
855 self.start.elapsed().as_secs_f64() * 1000.0
856 }
857 pub fn splits(&self) -> &[f64] {
859 &self.splits
860 }
861 pub fn num_splits(&self) -> usize {
863 self.splits.len()
864 }
865}
866#[allow(dead_code)]
868pub struct SparseVec<T: Default + Clone + PartialEq> {
869 entries: std::collections::HashMap<usize, T>,
870 default_: T,
871 logical_len: usize,
872}
873#[allow(dead_code)]
874impl<T: Default + Clone + PartialEq> SparseVec<T> {
875 pub fn new(len: usize) -> Self {
877 Self {
878 entries: std::collections::HashMap::new(),
879 default_: T::default(),
880 logical_len: len,
881 }
882 }
883 pub fn set(&mut self, idx: usize, val: T) {
885 if val == self.default_ {
886 self.entries.remove(&idx);
887 } else {
888 self.entries.insert(idx, val);
889 }
890 }
891 pub fn get(&self, idx: usize) -> &T {
893 self.entries.get(&idx).unwrap_or(&self.default_)
894 }
895 pub fn len(&self) -> usize {
897 self.logical_len
898 }
899 pub fn is_empty(&self) -> bool {
901 self.len() == 0
902 }
903 pub fn nnz(&self) -> usize {
905 self.entries.len()
906 }
907}
908#[allow(dead_code)]
910pub struct StackCalc {
911 stack: Vec<i64>,
912}
913#[allow(dead_code)]
914impl StackCalc {
915 pub fn new() -> Self {
917 Self { stack: Vec::new() }
918 }
919 pub fn push(&mut self, n: i64) {
921 self.stack.push(n);
922 }
923 pub fn add(&mut self) {
925 let b = self
926 .stack
927 .pop()
928 .expect("stack must have at least two values for add");
929 let a = self
930 .stack
931 .pop()
932 .expect("stack must have at least two values for add");
933 self.stack.push(a + b);
934 }
935 pub fn sub(&mut self) {
937 let b = self
938 .stack
939 .pop()
940 .expect("stack must have at least two values for sub");
941 let a = self
942 .stack
943 .pop()
944 .expect("stack must have at least two values for sub");
945 self.stack.push(a - b);
946 }
947 pub fn mul(&mut self) {
949 let b = self
950 .stack
951 .pop()
952 .expect("stack must have at least two values for mul");
953 let a = self
954 .stack
955 .pop()
956 .expect("stack must have at least two values for mul");
957 self.stack.push(a * b);
958 }
959 pub fn peek(&self) -> Option<i64> {
961 self.stack.last().copied()
962 }
963 pub fn depth(&self) -> usize {
965 self.stack.len()
966 }
967}
968#[allow(dead_code)]
970pub struct RewriteRuleSet {
971 rules: Vec<RewriteRule>,
972}
973#[allow(dead_code)]
974impl RewriteRuleSet {
975 pub fn new() -> Self {
977 Self { rules: Vec::new() }
978 }
979 pub fn add(&mut self, rule: RewriteRule) {
981 self.rules.push(rule);
982 }
983 pub fn len(&self) -> usize {
985 self.rules.len()
986 }
987 pub fn is_empty(&self) -> bool {
989 self.rules.is_empty()
990 }
991 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
993 self.rules.iter().filter(|r| r.conditional).collect()
994 }
995 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
997 self.rules.iter().filter(|r| !r.conditional).collect()
998 }
999 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
1001 self.rules.iter().find(|r| r.name == name)
1002 }
1003}
1004#[allow(dead_code)]
1006pub struct FlatSubstitution {
1007 pairs: Vec<(String, String)>,
1008}
1009#[allow(dead_code)]
1010impl FlatSubstitution {
1011 pub fn new() -> Self {
1013 Self { pairs: Vec::new() }
1014 }
1015 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
1017 self.pairs.push((from.into(), to.into()));
1018 }
1019 pub fn apply(&self, s: &str) -> String {
1021 let mut result = s.to_string();
1022 for (from, to) in &self.pairs {
1023 result = result.replace(from.as_str(), to.as_str());
1024 }
1025 result
1026 }
1027 pub fn len(&self) -> usize {
1029 self.pairs.len()
1030 }
1031 pub fn is_empty(&self) -> bool {
1033 self.pairs.is_empty()
1034 }
1035}
1036#[allow(dead_code)]
1038pub struct VersionedRecord<T: Clone> {
1039 history: Vec<T>,
1040}
1041#[allow(dead_code)]
1042impl<T: Clone> VersionedRecord<T> {
1043 pub fn new(initial: T) -> Self {
1045 Self {
1046 history: vec![initial],
1047 }
1048 }
1049 pub fn update(&mut self, val: T) {
1051 self.history.push(val);
1052 }
1053 pub fn current(&self) -> &T {
1055 self.history
1056 .last()
1057 .expect("VersionedRecord history is always non-empty after construction")
1058 }
1059 pub fn at_version(&self, n: usize) -> Option<&T> {
1061 self.history.get(n)
1062 }
1063 pub fn version(&self) -> usize {
1065 self.history.len() - 1
1066 }
1067 pub fn has_history(&self) -> bool {
1069 self.history.len() > 1
1070 }
1071}