blob: b4f801b70d3aca3e3f15b77c5837d2871703f872 (
plain)
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
66
67
68
69
70
71
72
73
74
|
#![macro_escape]
use std::ptr;
use std::cell::UnsafeCell;
use std::ops::Deref;
use std::boxed::FnBox;
pub enum State<V> {
Evaluated(V),
Evaluating,
Unevaluated(Box<FnBox() -> V>)
}
pub struct Lazy<V> {
state: UnsafeCell<State<V>>,
}
impl<V> Lazy<V> {
pub fn new(f: Box<FnBox() -> V>) -> Lazy<V> {
Lazy { state: UnsafeCell::new(State::Unevaluated(f)) }
}
pub fn ready(v: V) -> Lazy<V> {
Lazy { state: UnsafeCell::new(State::Evaluated(v)) }
}
pub fn force(&mut self) {
self.value();
}
pub fn unwrap(self) -> V {
unsafe {
match self.state.into_inner() {
State::Unevaluated(f) => f(),
State::Evaluating => panic!("Illegal state, can't call unwrap during evaluation"),
State::Evaluated(v) => v
}
}
}
pub fn value(&self) -> &V {
unsafe {
let state = self.state.get();
match *state {
State::Evaluated(ref v) => v,
State::Evaluating => panic!("Illegal state, can't call value during evaluation"),
State::Unevaluated(_) => {
if let State::Unevaluated(f) = ptr::replace(state, State::Evaluating) {
ptr::replace(state, State::Evaluated(f()));
}
if let State::Evaluated(ref v) = *state { return v }
unreachable!()
}
}
}
}
}
impl<V> Deref for Lazy<V> {
type Target = V;
fn deref(&self) -> &V { self.value() }
}
#[macro_export]
macro_rules! lazy {
(@as_expr $val: expr) => { $val };
($($val: tt)*) => { Lazy::new(Box::new(move || lazy![@as_expr { $($val)* }])) };
}
#[macro_export]
macro_rules! eager {
(@as_expr $val: expr) => { $val };
($($val: tt)*) => { Lazy::<_>::ready(eager![@as_expr { $($val)* }]) };
}
|