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}