1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
// Copyright 2020-2021 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 /// A macro for defining functions whose return values will wrapped in a `Cache`. /// /// # Example /// ``` /// use engine::cache; /// /// cache! { /// fn fib(n: u32) -> u32 => { /// match n { /// 0 => 1, /// 1 => 1, /// _ => fib(n - 1) + fib(n - 2), /// } /// } /// } /// /// assert_eq!(fib(20), 10946); /// assert_eq!(FIB_CACHE.lock().unwrap().get(&20), Some(&10946)); /// ``` #[macro_export] macro_rules! cache { (fn $name:ident ($($arg:ident: $arg_type:ty), *) -> $ret:ty => $body:expr) => { use once_cell::sync::Lazy; use std::sync::Mutex; use engine::store::Cache; use paste::paste; paste! { // create a static instance of `Cache<K, V>` for the expression called `$EXPR_NAME_CACHE`. static [<$name:upper _CACHE>]: Lazy<Mutex<Cache<($($arg_type),*), $ret>>> = Lazy::new(|| Mutex::new(Cache::new())); #[allow(unused_parens)] fn $name($($arg: $arg_type), *) -> $ret { // create a static instance of `Cache<K, V>` // static CACHE: Lazy<Mutex<Cache<($($arg_type),*), $ret>>> = // Lazy::new(|| Mutex::new(Cache::new())); // create key out of arg. let key = ($($arg.clone()), *); // get mutex to check for cached value. let cache = [<$name:upper _CACHE>].lock().unwrap(); // check for cached value. match cache.get(&key) { // if value is cached, return it. Some(val) => val.clone(), None => { // drop the mutex before execution to avoid a deadlock. drop(cache); // execute the body of the function/expression. let value = (||$body)(); // re-get mutex to add/update the cache. let mut cache = [<$name:upper _CACHE>].lock().unwrap(); cache.insert(key, value, None); value.clone() } } } } }; }