clvm_tools_rs/compiler/
stackvisit.rs1use std::mem::swap;
2
3pub trait HasDepthLimit<L, E> {
4 fn depth_limit(&self) -> Option<usize>;
5 fn stack_err(&self, loc: L) -> E;
6}
7
8pub trait Unvisit<T> {
9 fn give_back(&mut self, info: Option<Box<T>>);
10 fn take(&mut self) -> Option<Box<T>>;
11 fn depth(&self) -> usize;
12}
13
14pub struct VisitedMarker<'info, T> {
15 pub info: Option<Box<T>>,
16 pub prev: Option<&'info mut dyn Unvisit<T>>,
17 pub depth: usize,
18}
19
20impl<'info, T> VisitedMarker<'info, T> {
21 pub fn new(info: T) -> VisitedMarker<'static, T> {
22 VisitedMarker {
23 info: Some(Box::new(info)),
24 prev: None,
25 depth: 1,
26 }
27 }
28
29 pub fn again<L, E>(
31 loc: L,
32 prev: &'info mut dyn Unvisit<T>,
33 ) -> Result<VisitedMarker<'info, T>, E>
34 where
35 T: HasDepthLimit<L, E>,
36 {
37 let info = prev.take();
38 let depth = prev.depth();
39 if let Some(ref info) = info {
40 if let Some(limit) = info.depth_limit() {
41 if depth >= limit {
42 return Err(info.stack_err(loc));
43 }
44 }
45 }
46 Ok(VisitedMarker {
47 info,
48 prev: Some(prev),
49 depth: depth + 1,
50 })
51 }
52}
53
54impl<T> Unvisit<T> for VisitedMarker<'_, T> {
55 fn give_back(&mut self, info: Option<Box<T>>) {
56 self.info = info;
57 }
58 fn take(&mut self) -> Option<Box<T>> {
59 let mut info = None;
60 swap(&mut self.info, &mut info);
61 info
62 }
63 fn depth(&self) -> usize {
64 self.depth
65 }
66}
67
68impl<T> Drop for VisitedMarker<'_, T> {
70 fn drop(&mut self) {
71 let mut info = None;
72 swap(&mut self.info, &mut info);
73 if let Some(ref mut prev) = self.prev {
74 prev.give_back(info);
75 }
76 }
77}