use std::ops::{Deref, DerefMut};
use oncemutex::OnceMutex;
use std::mem;
use std::thunk::Invoke;
use self::Inner::{Evaluated, EvaluationInProgress, Unevaluated};
pub type Lazy<T> = Thunk<T>;
pub struct Thunk<T> {
inner: OnceMutex<Inner<T>>
}
unsafe impl<T: Sync> Sync for Thunk<T> {}
impl<T: Send + Sync> Thunk<T> {
pub fn new<F: 'static>(producer: F) -> Thunk<T>
where F: Send + Sync + FnOnce() -> T {
Thunk {
inner: OnceMutex::new(Unevaluated(Producer::new(producer)))
}
}
pub fn evaluated(val: T) -> Thunk<T> {
let mutex = OnceMutex::new(Evaluated(val));
mutex.lock();
Thunk { inner: mutex }
}
pub fn force(&self) {
match self.inner.lock() {
Some(mut lock) => {
match mem::replace(&mut *lock, EvaluationInProgress) {
Unevaluated(producer) => *lock = Evaluated(producer.invoke()),
_ => unsafe { debug_unreachable!() }
}
},
None => self.inner.wait()
}
}
}
impl<T: Send + Sync> DerefMut for Thunk<T> {
fn deref_mut(&mut self) -> &mut T {
self.force();
match *&mut*self.inner {
Evaluated(ref mut val) => unsafe { mem::transmute(val) },
_ => unsafe { debug_unreachable!() }
}
}
}
impl<T: Send + Sync> Deref for Thunk<T> {
type Target = T;
fn deref(&self) -> &T {
self.force();
match *self.inner {
Evaluated(ref val) => unsafe { mem::copy_lifetime(self, val) },
_ => unsafe { debug_unreachable!() }
}
}
}
struct Producer<T> {
inner: Box<Invoke<(), T> + Send + Sync>
}
impl<T> Producer<T> {
fn new<F: 'static + Send + Sync + FnOnce() -> T>(f: F) -> Producer<T> {
Producer {
inner: Box::new(move |()| {
f()
}) as Box<Invoke<(), T> + Send + Sync>
}
}
fn invoke(self) -> T {
self.inner.invoke(())
}
}
enum Inner<T> {
Evaluated(T),
EvaluationInProgress,
Unevaluated(Producer<T>)
}