1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
extern crate alloc;

use core::cell::UnsafeCell;

enum Value<T, U> {
    Init(T),
    Final(U),
}

pub struct LazyTransform<F, T, U> {
    transform: F,
    value: UnsafeCell<Value<T, U>>,
}

impl<F: Fn(&T) -> U, T, U> LazyTransform<F, T, U> {
    pub fn new<'a>(init: T, f: F) -> LazyTransform<F, T, U> {
        LazyTransform {
            transform: f,
            value: Value::Init(init).into(),
        }
    }
    pub fn get(&self) -> &U {
        let value = unsafe { &mut *self.value.get() };
        match value {
            Value::Init(v) => {
                let final_value = (self.transform)(v);
                *value = Value::Final(final_value);
                match value {
                    Value::Init(_) => unreachable!(),
                    Value::Final(ref final_value) => final_value,
                }
            }
            Value::Final(v) => v,
        }
    }
}

#[cfg(tests)]
mod test {
    fn add_one(x: &i32) -> i32 {
        x + 1
    }
    #[test]
    fn it_works() {
        use crate::LazyTransform;
        let lazy = LazyTransform::new(1, |x| x + 1);
        assert_eq!(*lazy.get(), 2);
        assert_eq!(*lazy.get(), 2);
        let lazy = LazyTransform::new(10, add_one);
        assert_eq!(*lazy.get(), 11);
        assert_eq!(*lazy.get(), 11);
    }
}