use std::thread;
use std::time::Duration;
use std::collections::HashMap;
pub struct Cacher<T, P, O>
where T: Fn(P) -> O,
P: std::cmp::Eq + std::hash::Hash + Copy,
O: Copy
{
pub caculation: T,
pub value: HashMap<P, O>,
}
impl<T, P, O> Cacher<T, P, O>
where T: Fn(P) -> O,
P: std::cmp::Eq + std::hash::Hash + Copy,
O: Copy
{
pub fn new(caculation: T) -> Cacher<T, P, O> {
Cacher {
caculation,
value: HashMap::new(),
}
}
pub fn value(&mut self, arg: P) -> O {
let ret = match self.value.get(&arg) {
Some(v) => *v,
None => {
let v = (self.caculation)(arg);
v
}
};
self.value.insert(arg, ret);
ret
}
}
pub fn generate_workout(intensity: u32, random_number: u32) {
let mut expensive_result = Cacher::new(|num| {
println!("calculating slowly...");
thread::sleep(Duration::from_secs(2));
num
});
if intensity < 25 {
println!(
"Today, do {} pushups!",
expensive_result.value(intensity)
);
println!(
"Next, do {} situps!",
expensive_result.value(intensity)
);
} else {
if random_number == 3 {
println!("Take a break today! Remember to stay hydrated!");
} else {
println!(
"Today, run for {} minutes!",
expensive_result.value(intensity)
);
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn call_with_different_values() {
let mut c = Cacher::new(|a| a);
let _v1 = c.value(1);
let v2 = c.value(2);
assert_eq!(v2, 2);
}
#[test]
fn call_with_different_values_2() {
let mut c = Cacher::new(|mystring: &str| mystring.len());
let _v1 = c.value("abc");
let v2 = c.value("abcde");
assert_eq!(v2, 5);
}
}