cacher fixed

unlisted ⁨1⁩ ⁨file⁩ 2019-07-31 13:46:34 UTC

cacher.rs

Raw
use std::thread;
use std::time::Duration;
use std::collections::HashMap;

struct Cacher<T, P, R>
    where T: Fn(&P) -> R,
          P: std::cmp::Eq + std::hash::Hash
{
    calculation: T,
    values: HashMap<P, R>,
}

impl<T, P, R> Cacher<T, P, R>
    where T: Fn(&P) -> R,
          P: std::cmp::Eq + std::hash::Hash
{
    fn new(calculation: T) -> Cacher<T, P, R> {
        Cacher {
            calculation,
            values: HashMap::new(),
        }
    }

    fn value(&mut self, arg: P) -> &R {
        use std::collections::hash_map::Entry;
        match self.values.entry(arg) {
            Entry::Occupied(entry) => entry.into_mut(),
            Entry::Vacant(entry) => {
                let v = (self.calculation)(entry.key());
                entry.insert(v)
            }
        }
    }
}

fn generate_workout(intensity: u32, random_number: u32) {
    let mut expensive_result = Cacher::new(|num| {
        println!("calculating...");
        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)
            );
        }
    }
}

fn main() {
    let simulated_user_specified_value = 10;
    let simulated_random_number = 7;

    generate_workout(
        simulated_user_specified_value,
        simulated_random_number
    );
}

#[cfg(test)]
mod tests {
    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 value_can_differ_return_type_from_parameter_type() {
        let mut c = Cacher::new(|_a| String::from("hello"));

        let v = c.value(5);
        assert_eq!(*v, "hello");
    }
}