clvm_tools_rs/compiler/
stackvisit.rs

1use 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    // Each new level takes the info box and adds one depth.
30    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
68// When dropped, the info box is handed back.
69impl<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}