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}