lazy_transform/
lib.rs

1#![no_std]
2
3extern crate alloc;
4
5use core::cell::UnsafeCell;
6
7enum Value<T, U> {
8    Init(T),
9    Final(U),
10}
11
12pub struct LazyTransform<F, T, U> {
13    transform: F,
14    value: UnsafeCell<Value<T, U>>,
15}
16
17impl<F: Fn(&T) -> U, T, U> LazyTransform<F, T, U> {
18    pub fn new<'a>(init: T, f: F) -> LazyTransform<F, T, U> {
19        LazyTransform {
20            transform: f,
21            value: Value::Init(init).into(),
22        }
23    }
24    pub fn get(&self) -> &U {
25        let value = unsafe { &mut *self.value.get() };
26        match value {
27            Value::Init(v) => {
28                let final_value = (self.transform)(v);
29                *value = Value::Final(final_value);
30                match value {
31                    Value::Init(_) => unreachable!(),
32                    Value::Final(ref final_value) => final_value,
33                }
34            }
35            Value::Final(v) => v,
36        }
37    }
38}
39
40#[cfg(tests)]
41mod test {
42    fn add_one(x: &i32) -> i32 {
43        x + 1
44    }
45    #[test]
46    fn it_works() {
47        use crate::LazyTransform;
48        let lazy = LazyTransform::new(1, |x| x + 1);
49        assert_eq!(*lazy.get(), 2);
50        assert_eq!(*lazy.get(), 2);
51        let lazy = LazyTransform::new(10, add_one);
52        assert_eq!(*lazy.get(), 11);
53        assert_eq!(*lazy.get(), 11);
54    }
55}