thunk_simple/
lib.rs

1//! Simpler alternative to the `thunk` crate, containing only one `Thunk` type, and conversion between Iterators and Thunks
2
3/// The `Thunk<T>` type.
4/// This type is not evaluated until the `unwrap` method is called.
5/// The inner value cannot be referenced until it's unwrapped.
6pub struct Thunk<'f,T>(Box<dyn (FnOnce()-> T) + 'f>) where T: 'f;
7
8impl<'f,T> Thunk<'f,T> where T:'f {
9
10    /// Create a new `Thunk<T>` from a closure or function returning `T`
11    pub fn new<NT,NF>(body: NF) -> Thunk<'f,NT> where
12        NF: (FnOnce() -> NT) + 'f
13    {
14        Thunk(Box::new(body))
15    }
16
17    /// Create a new `Thunk<T>` from an already-calculated value T
18    pub fn new_const<NT: 'f>(nt: NT) -> Thunk<'f,NT> {
19        Self::new(|| nt)
20    }
21
22    /// Map a `Thunk<T>` into a `Thunk<U>`.
23    /// This method supplies the previous thunk value unevaluated as an argument.
24    pub fn map_lazy<NT,NF>(self,body: NF) -> Thunk<'f,NT> where
25        NF: (FnOnce(Thunk<'f,T>) -> NT) + 'f
26    {
27        Thunk::<'f,NT>::new(|| (body)(self))
28    }
29
30    /// Map a `Thunk<T>` into a `Thunk<U>`.
31    /// This method provides an already-evaluated T to the mapping function
32    pub fn map<NT,NF>(self,body: NF) -> Thunk<'f,NT> where
33        NF: (FnOnce(T) -> NT) + 'f
34    {
35        Thunk::<'f,NT>::new(|| (body)((self.0)()))
36    }
37
38    /// Unwrap, and therefore calculate, the value `T` contained inside this thunk
39    /// 
40    /// ## Panics
41    /// If the Thunk was created `from` an Iterator, the Thunk may panic if the Iterator yields less than one element.
42    /// Otherwise only panics when any function involved in calculating the value panics.
43    pub fn unwrap(self) -> T {
44        (self.0)()
45    }
46
47}
48
49impl<'f,T,I> From<I> for Thunk<'f,T> where
50    T: 'f,
51    I: Iterator<Item = T> + 'f
52{
53    fn from(mut iter: I) -> Self {
54        Self::new(move || iter.next().unwrap())
55    }
56}
57
58impl<'f,T> IntoIterator for Thunk<'f,T> where
59    T: 'f
60{
61    type IntoIter = IntoIter<'f,T>;
62    type Item = T;
63
64    fn into_iter(self) -> Self::IntoIter {
65        IntoIter(Some(self))
66    }
67}
68
69/// Simple IntoIter Iterator, that yields the value of the Thunk then None
70pub struct IntoIter<'f,T>(Option<Thunk<'f,T>>);
71
72impl<'f,T> Iterator for IntoIter<'f,T> {
73    type Item = T;
74    fn next(&mut self) -> Option<Self::Item> {
75        if let Some(thunk) = std::mem::take(&mut self.0) {
76            Some(thunk.unwrap())
77        } else {
78            None
79        }
80    }
81}