function_cache/
lib.rs

1//! # function_cache
2//!
3//! A type that automatically caches the result of a function.
4
5use std::cmp::Eq;
6use std::hash::Hash;
7use std::collections::HashMap;
8
9/// Wraps an immutable function such that the results of its invocation
10/// are cached to a `HashMap<TInput, TReturn>`.
11pub struct CachedFunction<TFunction, TInput, TReturn>
12where 
13    TFunction : Fn(TInput) -> TReturn,
14    TInput : Eq + Hash + Copy,
15    TReturn: Copy
16{
17    calculation: TFunction,
18    values: HashMap<TInput, TReturn>
19}
20
21impl<TFunction, TInput, TReturn> CachedFunction<TFunction, TInput, TReturn>
22where 
23    TFunction : Fn(TInput) -> TReturn,
24    TInput : Eq + Hash + Copy,
25    TReturn: Copy
26{
27    /// Returns a `CachedFunction<TFunction, TInput, TReturn>` that wraps the input function.
28    /// 
29    /// # Arguments
30    /// 
31    /// * `function` - The function to wrap in a cache.
32    /// 
33    /// # Examples
34    /// 
35    /// ```
36    /// use std::thread;
37    /// use std::time::Duration;
38    /// use function_cache::CachedFunction;
39    /// 
40    /// let mut cached_function = CachedFunction::new(|x: i32| {
41    ///     thread::sleep(Duration::from_secs(2));
42    ///     x
43    /// });
44    /// ```
45    pub fn new(function: TFunction) -> CachedFunction<TFunction, TInput, TReturn> {
46        CachedFunction {
47            calculation: function,
48            values: HashMap::new()
49        }
50    }
51
52    /// Gets the value of evaluating the function with the `arg` as input. First,
53    /// the cache is checked and if the value with `arg` has already be computed, it
54    /// will be returned from the cache.
55    /// 
56    /// # Arguments
57    /// 
58    /// * `arg` - The argument to the function call.
59    pub fn value(&mut self, arg: TInput) -> TReturn {
60        if self.values.contains_key(&arg) {
61            self.values[&arg]
62        }
63        else {
64            let value = (self.calculation)(arg);
65            self.values.insert(arg, value);
66            value
67        }
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn cached_function_value_returns_expected_value() {
77        let input = 4;
78        let closure = |x: i32| x * x;
79        let expected = closure(input);
80        let mut function = CachedFunction::new(closure);
81
82        let actual = function.value(input);
83
84        assert_eq!(expected, actual);
85    }
86
87    #[test]
88    fn cached_function_returns_expected_value_on_subsequent_calls() {
89        let input = 4;
90        let mut function = CachedFunction::new(|x: i32| x * x);
91        let expected = function.value(input);
92        let actual = function.value(input);
93
94        assert_eq!(expected, actual);
95    }
96}