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
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use std::ops::{Deref, DerefMut};

use ::{LazyRef, LazyMut, Lazy};


/// A do-nothing, strict "thunk". This is intended for implementing structures which
/// are generic over strictness.
#[derive(Clone, Copy)]
pub struct Strict<T>(T);


impl<T> From<T> for Strict<T> {
    fn from(t: T) -> Strict<T> {
        Strict(t)
    }
}


impl<T> AsRef<T> for Strict<T> {
    fn as_ref(&self) -> &T {
        &self.0
    }
}


impl<T> AsMut<T> for Strict<T> {
    fn as_mut(&mut self) -> &mut T {
        &mut self.0
    }
}


impl<T> Deref for Strict<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.0
    }
}


impl<T> DerefMut for Strict<T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut self.0
    }
}


impl<T> LazyRef for Strict<T> {
    #[inline]
    fn defer<'a, F: FnOnce() -> T + 'a>(f: F) -> Strict<T> {
        Strict(f())
    }


    #[inline]
    fn force(&self) {}
}


impl<T> LazyMut for Strict<T> {}


impl<T> Lazy for Strict<T> {
    #[inline]
    fn unwrap(self) -> T { self.0 }
}


#[cfg(test)]
mod test {
    use super::*;

    use test::{self, Bencher};

    #[test]
    fn thunk_computed() {
        let thunk = Strict::computed(1 + 1);

        assert_eq!(*thunk, 2);
    }

    #[test]
    fn thunk_deferred() {
        let thunk = Strict::defer(|| test::black_box(1) + 1);

        assert_eq!(*thunk, 2);
    }

    fn ten_thousand_xors_strict(n: usize) -> Strict<usize> {
        Strict::computed((0..test::black_box(10000)).fold(test::black_box(n), |old, new| old ^ new))
    }

    fn ten_thousand_xors_lazy(n: usize) -> Strict<usize> {
        Strict::defer(move || {
                         (0..test::black_box(10000)).fold(test::black_box(n), |old, new| old ^ new)
                     })
    }

    #[bench]
    fn ten_thousand_xors_threadsafe_strict(b: &mut Bencher) {
        b.iter(|| {
                   let mut things: Vec<_> = (0..1000).map(ten_thousand_xors_strict).collect();
                   test::black_box(things.pop())
               })
    }

    #[bench]
    fn ten_thousand_xors_threadsafe_lazy(b: &mut Bencher) {
        b.iter(|| {
            let mut things: Vec<_> = (0..1000).map(ten_thousand_xors_lazy).collect();
            test::black_box(things.pop())
        })
    }
}