use std::ops::Deref;
use std::cell::UnsafeCell;
use std::rc::Rc;
use std::mem;
use std::fmt;
use self::Inner::{Evaluated, EvaluationInProgress, Unevaluated, Redirect};
#[macro_export]
macro_rules! lazy {
($($e: stmt);*) => {
$crate::lazy::Thunk::new(move || { $($e);* })
}
}
#[macro_export]
macro_rules! lazy_val {
($($e: stmt);*) => {
$crate::lazy::Thunk::new(move || { value({$($e);*}) })
}
}
#[macro_export]
macro_rules! lazy_redirect {
($($e: stmt);*) => {
$crate::lazy::Thunk::new(move || { redirect({$($e);*}) })
}
}
pub fn strict<T>(v: T) -> Thunk<T> {
Thunk::evaluated(v)
}
pub fn redirect<T>(t: Thunk<T>) -> ThunkResult<T> {
ThunkResult::Redirect(t)
}
pub fn value<T>(v: T) -> ThunkResult<T> {
ThunkResult::Value(v)
}
pub type Lazy<T> = Thunk<T>;
pub struct Thunk<T> (UnsafeCell<Rc<UnsafeCell<Inner<T>>>>);
impl<T> Thunk<T> {
pub fn new<F>(producer: F) -> Thunk<T>
where F: FnOnce() -> ThunkResult<T> + 'static {
Thunk(UnsafeCell::new(Rc::new(UnsafeCell::new(Unevaluated(Producer::new(producer))))))
}
pub fn evaluated(val: T) -> Thunk<T> {
Thunk(UnsafeCell::new(Rc::new(UnsafeCell::new(Evaluated(val)))))
}
pub fn force(&self) {
loop {
match *self.inner() {
Evaluated(_) => return,
EvaluationInProgress => {
panic!("Thunk::force called recursively. (A Thunk tried to force itself while trying to force itself).")
},
Redirect(ref t) => {
self.redirect(t.clone());
continue;
},
Unevaluated(_) => ()
};
break;
}
match mem::replace(self.inner(), EvaluationInProgress) {
Unevaluated(producer) => {
*self.inner() = EvaluationInProgress;
match producer.invoke() {
ThunkResult::Value(x) =>
*self.inner() = Evaluated(x),
ThunkResult::Redirect(t) => {
t.force();
*self.inner() = Redirect(t.clone());
self.redirect(t);
}
}
}
_ => {
let x = 42;
println!("thats not good {}",x);
}
}
}
fn inner(&self) -> &mut Inner<T> {
match *self {
Thunk(ref cell) => unsafe {
&mut *(**cell.get()).get()
}
}
}
fn rc(&self) -> &mut Rc<UnsafeCell<Inner<T>>> {
match *self {
Thunk(ref cell) => unsafe {
&mut *cell.get()
}
}
}
fn redirect(&self, t: Thunk<T>) {
*self.rc() = t.rc().clone();
}
}
impl<T> Deref for Thunk<T> {
type Target = T;
fn deref(&self) -> &T {
self.force();
match *self.inner() {
Evaluated(ref val) => val,
_ => unreachable!(),
}
}
}
impl<T> Clone for Thunk<T> {
fn clone(&self) -> Thunk<T> {
Thunk(UnsafeCell::new(self.rc().clone()))
}
}
impl<T> fmt::Debug for Thunk<T>
where T: fmt::Debug
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("Thunk")
.field(self.inner())
.finish()
}
}
#[derive(Debug)]
pub enum ThunkResult<T> {
Value(T),
Redirect(Thunk<T>)
}
struct Producer<T> {
inner: Box<Invoke<T>>
}
impl<T> fmt::Debug for Producer<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Producer{{...}}")
}
}
impl<T> Producer<T> {
fn new<F: FnOnce() -> T + 'static>(f: F) -> Producer<T> {
Producer {
inner: Box::new(move || {
f()
}) as Box<Invoke<T>>
}
}
fn invoke(self) -> T {
self.inner.invoke()
}
}
#[derive(Debug)]
enum Inner<T> {
Evaluated(T),
EvaluationInProgress,
Unevaluated(Producer<ThunkResult<T>>),
Redirect(Thunk<T>),
}
#[doc(hidden)]
pub trait Invoke<T> {
fn invoke(self: Box<Self>) -> T;
}
impl<T, F> Invoke<T> for F
where F: FnOnce() -> T
{
fn invoke(self: Box<F>) -> T {
let f = *self;
f()
}
}