diff options
author | Till Höppner | 2016-02-23 17:00:53 +0100 |
---|---|---|
committer | Till Höppner | 2016-02-24 18:36:04 +0100 |
commit | f01c278a26e0f248d188c10bdb852b0859b98b3b (patch) | |
tree | 3e729bf243011111a20b84f24aea3fbcb9f595f5 /src/lazy.rs | |
parent | 815f31f5cef61709c50087c9f7601ea330929bb7 (diff) | |
download | ilc-f01c278a26e0f248d188c10bdb852b0859b98b3b.tar.gz ilc-f01c278a26e0f248d188c10bdb852b0859b98b3b.tar.xz ilc-f01c278a26e0f248d188c10bdb852b0859b98b3b.zip |
Test CI
Diffstat (limited to 'src/lazy.rs')
-rw-r--r-- | src/lazy.rs | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/src/lazy.rs b/src/lazy.rs new file mode 100644 index 0000000..b4f801b --- /dev/null +++ b/src/lazy.rs @@ -0,0 +1,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)* }]) }; +} |