Cacher

unlisted ⁨1⁩ ⁨file⁩ 2019-07-30 20:49:32 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 {
        self.values.entry(arg)
            .or_insert((self.calculation)(arg))
    }
}

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);
    }
}