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}