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
75
76
//! This crate provides functionality for thread-safe and non-thread-safe lazy
//! evaluation in Rust. It also provides functionality for generically working
//! with thunks of a given type.
//!
//! Three different owned thunk types are provided, implementing `Lazy`,
//! `LazyRef`, and `LazyMut`:
//! * `Thunk`: a non thread-safe thunk.
//! * `AtomicThunk`: a thread-safe thunk, which implements `Send + Sync`.
//! * `Strict`: a strict, non-deferred thunk which always immediately
//!   evaluates whatever computation it's given, intended for genericity over
//!   strictness.
//!
//! In addition, two shared thunk types are provided, implementing `LazyRef`
//! and `LazyShared`:
//! * `RcThunk`: a reference-counted thunk type. This is a wrapper over `Thunk`.
//! * `ArcThunk`: an atomically reference-counted thunk type. This is a wrapper
//!   over `AtomicThunk`.

#![cfg_attr(test, feature(test))]
#![feature(fnbox)]
#![feature(untagged_unions)]

extern crate unreachable;

#[cfg(test)]
extern crate test;

use std::ops::{Deref, DerefMut};

pub mod strict;
pub mod sync;
pub mod unsync;


pub use strict::Strict;
pub use sync::{AtomicThunk, ArcThunk};
pub use unsync::{Thunk, RcThunk};


/// The `Lazy` trait abstracts thunks which have exactly the same lifetimes
/// as the types they defer computation of.
pub trait LazyRef
    : Deref + Sized
    where Self::Target: Into<Self> + Sized
{
    /// Construct a thunk with a precomputed value. This means
    /// forcing the thunk is a no-op.
    #[inline]
    fn computed(t: Self::Target) -> Self {
        t.into()
    }

    /// Defer a computation stored as a `FnOnce` closure. Unwrapping/dereferencing
    /// will force the computation of the closure. The supplied closure must live
    /// as long as the type which the thunk computes.
    fn defer<'a, F: FnOnce() -> Self::Target + 'a>(F) -> Self where Self::Target: 'a;

    /// Manually force a thunk's computation.
    fn force(&self);
}


/// The `LazyMut` trait abstracts mutable references to lazily computed values.
pub trait LazyMut: From<<Self as Deref>::Target> + LazyRef + DerefMut
    where Self::Target: Sized
{
}


/// The `Lazy` trait abstracts owned, lazily computed values.
pub trait Lazy: LazyMut
    where Self::Target: Sized
{
    /// Unwrap a thunk into its inner value. This forces the thunk.
    fn unwrap(self) -> Self::Target;
}