kn_graph/optimizer/recurse.rs
1/// Trick to avoid stackoverflow on deep graphs:
2/// We don't recuse at all, and if we would have wanted to to recurse we return `Err` instead.
3/// This function then explicitly recuses using a heap-allocation stack by repeatedly calling `f`.
4///
5/// `f` _must_ be deterministic and have built-in caching.
6pub fn heap_recurse<X: Copy, Y: Clone>(x: X, mut f_cached: impl FnMut(X) -> Result<Y, X>) -> Y {
7 let mut stack = vec![x];
8
9 loop {
10 let curr = *stack.last().unwrap();
11
12 match f_cached(curr) {
13 Ok(y) => {
14 stack.pop().unwrap();
15 if stack.is_empty() {
16 return y;
17 }
18 }
19 Err(other_value) => stack.push(other_value),
20 }
21 }
22}