use kash::kash; use std::thread::{sleep, spawn}; use std::time::Duration; // `kash` shorthand, uses the default unbounded cache. #[kash] fn fib(n: u32) -> u32 { if n == 0 || n == 1 { return n; } fib(n - 1) + fib(n - 2) } #[kash(name = "FLIB")] fn fib_2(n: u32) -> u32 { if n == 0 || n == 1 { return n; } fib(n - 1) + fib(n - 2) } // Same as above, but pre-allocates some space. #[kash(size = "50")] fn fib_specific(n: u32) -> u32 { if n == 0 || n == 1 { return n; } fib_specific(n - 1) + fib_specific(n - 2) } // Specify a specific cache type // Note that the cache key type is a tuple of function argument types. #[kash(size = "100")] fn slow(a: u32, b: u32) -> u32 { sleep(Duration::new(2, 0)); a * b } // Specify a specific cache type and an explicit key expression // Note that the cache key type is a `String` created from the borrow arguments #[kash( size = "100", key(ty = "String", expr = r#"{ format!("{}{}", a, b) }"#) )] fn keyed(a: &str, b: &str) -> usize { let size = a.len() + b.len(); sleep(Duration::new(size as u64, 0)); size } #[kash(key(ty = "String", expr = r#"{ format!("{}{}", a, b) }"#))] fn keyed_key(a: &str, b: &str) -> usize { let size = a.len() + b.len(); sleep(Duration::new(size as u64, 0)); size } // handle results, don't cache errors #[kash(result)] fn slow_result(a: u32, b: u32) -> Result { sleep(Duration::new(2, 0)); Ok(a * b) } // A simple cache that expires after a second. We'll keep the // value fresh by priming it in a separate thread. #[kash(ttl = "1")] fn expires_for_priming(a: i32) -> i32 { a } pub fn main() { println!("\n ** default cache with default name **"); fib(3); fib(3); // { // let cache = FIB.clone(); // println!("hits: {:?}", cache.cache_hits()); // assert_eq!(cache.cache_hits().unwrap(), 2); // println!("misses: {:?}", cache.cache_misses()); // assert_eq!(cache.cache_misses(), Some(4)); // // make sure lock is dropped // } fib(10); fib(10); println!("\n ** default cache with explicit name **"); fib_2(3); fib_2(3); // { // let cache = FLIB.clone(); // println!("hits: {:?}", cache.cache_hits()); // assert_eq!(cache.cache_hits().unwrap(), 1); // println!("misses: {:?}", cache.cache_misses()); // assert_eq!(cache.cache_misses(), Some(1)); // // make sure lock is dropped // } println!("\n ** specific cache **"); fib_specific(20); fib_specific(20); // { // let cache = FIB_SPECIFIC.clone(); // println!("hits: {:?}", cache.cache_hits()); // assert_eq!(cache.cache_hits().unwrap(), 19); // println!("misses: {:?}", cache.cache_misses()); // assert_eq!(cache.cache_misses(), Some(21)); // // make sure lock is dropped // } fib_specific(20); fib_specific(20); println!("\n ** slow func **"); println!(" - first run `slow(10)`"); slow(10, 10); println!(" - second run `slow(10)`"); slow(10, 10); // { // let cache = SLOW.clone(); // println!("hits: {:?}", cache.cache_hits()); // assert_eq!(cache.cache_hits().unwrap(), 1); // println!("misses: {:?}", cache.cache_misses()); // assert_eq!(cache.cache_misses().unwrap(), 1); // // make sure the cache-lock is dropped // } println!("\n ** slow result func **"); println!(" - first run `slow_result(10)`"); let _ = slow_result(10, 10); println!(" - second run `slow_result(10)`"); let _ = slow_result(10, 10); // { // let cache = SLOW_RESULT.clone(); // println!("hits: {:?}", cache.cache_hits()); // assert_eq!(cache.cache_hits().unwrap(), 1); // println!("misses: {:?}", cache.cache_misses()); // assert_eq!(cache.cache_misses(), Some(1)); // // make sure the cache-lock is dropped // } println!("\n ** refresh by priming **"); let h = spawn(|| { for _ in 1..6 { expires_for_priming_prime_cache(1); sleep(Duration::from_millis(500)); } }); sleep(Duration::from_millis(200)); for _n in 1..6 { assert_eq!(1, expires_for_priming(1)); // { // let c = EXPIRES_FOR_PRIMING.clone(); // assert_eq!(n, c.cache_hits().unwrap()); // assert_eq!(0, c.cache_misses().unwrap()); // println!( // "primed cache hits: {}, misses: {}", // c.cache_hits().unwrap(), // c.cache_misses().unwrap() // ); // } sleep(Duration::from_millis(500)); } h.join().unwrap(); println!("now wait for expiration"); sleep(Duration::from_millis(1000)); assert_eq!(1, expires_for_priming(1)); // { // let c = EXPIRES_FOR_PRIMING.clone(); // assert_eq!(5, c.cache_hits().unwrap()); // assert_eq!(1, c.cache_misses().unwrap()); // println!( // "primed cache hits: {}, misses: {}", // c.cache_hits().unwrap(), // c.cache_misses().unwrap() // ); // } println!("\ndone!"); }