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
54
55
use std::sync::Arc;
use std::sync::Mutex;

pub struct Lazy<A> {
    data: Arc<Mutex<LazyData<A>>>
}

impl<A> Clone for Lazy<A> {
    fn clone(&self) -> Self {
        Lazy {
            data: self.data.clone()
        }
    }
}

pub enum LazyData<A> {
    Thunk(Box<dyn FnMut()->A+Send>),
    Value(A)
}

impl<A:Send+Clone+'static> Lazy<A> {

    pub fn new<THUNK:FnMut()->A+Send+'static>(thunk: THUNK) -> Lazy<A> {
        Lazy {
            data: Arc::new(Mutex::new(LazyData::Thunk(Box::new(thunk))))
        }
    }

    pub fn of_value(value: A) -> Lazy<A> {
        Lazy {
            data: Arc::new(Mutex::new(LazyData::Value(value)))
        }
    }

    pub fn run(&self) -> A {
        let mut l = self.data.lock();
        let data: &mut LazyData<A> = l.as_mut().unwrap();
        let next_op: Option<LazyData<A>>;
        let result: A;
        match data {
            &mut LazyData::Thunk(ref mut k) => {
                result = k();
                next_op = Some(LazyData::Value(result.clone()));
            },
            &mut LazyData::Value(ref x) => {
                result = x.clone();
                next_op = None;
            }
        }
        if let Some(next) = next_op {
            *data = next;
        }
        result
    }
}