lazy_scoped/
lib.rs

1#![cfg_attr(nightly, feature(fnbox))]
2
3use std::cell::RefCell;
4use std::ops::Deref;
5use std::mem::transmute;
6use std::mem::replace;
7
8#[cfg(nightly)]
9use std::boxed::FnBox;
10
11#[cfg(nightly)]
12pub struct Lazy<T, F = Box<FnBox() -> T>> where F: FnOnce() -> T {
13    store: RefCell<LazyStorage<T, F>>,
14}
15
16#[cfg(not(nightly))]
17pub struct Lazy<T, F> where F: FnOnce() -> T {
18    store: RefCell<LazyStorage<T, F>>,
19}
20
21enum LazyStorage<T, F> where F: FnOnce() -> T {
22    Func(F),
23    Stored(Option<T>),
24}
25
26impl<T, F> LazyStorage<T, F> where F: FnOnce() -> T {
27    fn as_ref(&self) -> Option<&T> {
28        match *self {
29            LazyStorage::Stored(Some(ref t)) => Some(t),
30            _ => None,
31        }
32    }
33
34    fn consume(&mut self) -> Option<T> {
35        match *self {
36            LazyStorage::Stored(ref mut opt) => replace(opt, None),
37            _ => None,
38        }
39    }
40}
41
42impl<T, F> Lazy<T, F> where F: FnOnce() -> T {
43    pub fn new(f: F) -> Lazy<T, F> {
44        Lazy {
45            store: RefCell::new(LazyStorage::Func(f)),
46        }
47    }
48
49    pub fn consume(self) -> T {
50        self.consume_fn();
51
52        self.store.borrow_mut().consume().unwrap()
53    }
54
55    fn consume_fn(&self) {
56        use self::LazyStorage::*;
57
58        if let Stored(_) = *self.store.borrow() {
59            return;
60        }
61
62        let f = match replace(
63            &mut *self.store.borrow_mut(),
64            Stored(None)
65        ) {
66            Func(f) => f,
67            _ => unreachable!(),
68        };
69
70        *self.store.borrow_mut() = Stored(Some(f()));
71    }
72}
73
74impl<T, F> Deref for Lazy<T, F> where F: FnOnce() -> T {
75    type Target = T;
76
77    fn deref(&self) -> &T {
78        self.consume_fn();
79        unsafe { transmute(self.store.borrow().as_ref().unwrap()) }
80    }
81}