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
56
57
58
59
60
61
62
63
64
65
use std::sync::{Arc, Mutex, RwLock};
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::SeqCst;

pub struct MaybeSingle<T> {
    data: Arc<RwLock<Option<T>>>,
    init: fn() -> T,
    callers: Arc<Mutex<AtomicUsize>>
}

impl <T> MaybeSingle<T> {

    pub fn new(init: fn() -> T) -> Self {
        MaybeSingle {
            data: Arc::new(RwLock::new(None)),
            init,
            callers: Arc::new(Mutex::new(AtomicUsize::new(0)))
        }
    }

    pub fn get<F: FnOnce(&T)>(&self, callback: F) {

        //let rnd: u16 = rand::thread_rng().gen();

        //println!("---- Start {}", rnd);

        {
            let lock= self.callers.lock().unwrap();
            let callers = lock.load(SeqCst) + 1;
            lock.store(callers, SeqCst);
        }
        {
            let mut lock = self.data.write().unwrap();

            lock = if lock.is_none() {
                drop(lock);
                {
                    let mut write_lock = self.data.write().unwrap();
                    *write_lock = Some((self.init)());
                }
                self.data.write().unwrap()
            } else {
                lock
            };

            //println!("---- Exec {}", rnd);
            match lock.as_ref() {
                Some(data) => callback(data),
                None => panic!("There should always be data here!")
            };
        }
        {
            let lock= self.callers.lock().unwrap();
            let callers = lock.load(SeqCst) - 1;
            lock.store(callers, SeqCst);

            if callers == 0 {
                let mut data = self.data.write().unwrap();
                *data = None;
            }
        }
        //println!("---- End {}", rnd);

    }
}