Gets the value from the cache if it exists, else tries to insert the result of the fn `f` into the cache and returns the same
(
&self,
key: K,
f: impl FnOnce() -> Result<V, E>,
)
| 234 | /// insert the result of the fn `f` into the cache and returns the |
| 235 | /// same |
| 236 | pub fn get_or_insert<E>( |
| 237 | &self, |
| 238 | key: K, |
| 239 | f: impl FnOnce() -> Result<V, E>, |
| 240 | ) -> Result<CachedValue<V>, E> { |
| 241 | let mut inserted = false; |
| 242 | let k1 = key.clone(); |
| 243 | let k2 = key.clone(); |
| 244 | let res = self |
| 245 | .map |
| 246 | .entry(key) |
| 247 | .and_modify(|(_, counter)| { |
| 248 | let old_counter = *counter; |
| 249 | let new_counter = self.increment_counter(); |
| 250 | self.index.on_cache_hit(old_counter, new_counter, k1.into()); |
| 251 | *counter = new_counter; |
| 252 | }) |
| 253 | .or_try_insert_with(|| { |
| 254 | inserted = true; |
| 255 | let counter = self.increment_counter(); |
| 256 | self.index.on_cache_miss(counter, k2.into()); |
| 257 | f().map(|v| (v, counter)) |
| 258 | }) |
| 259 | .map(|v| v.0.clone()); |
| 260 | // @NOTE: We need to clone the value before calling |
| 261 | // `self.evict`, that too in a separate block! Otherwise |
| 262 | // it causes some deadlock |
| 263 | match res { |
| 264 | Ok(v) => { |
| 265 | if inserted { |
| 266 | self.evict(); |
| 267 | Ok(CachedValue::Miss(v)) |
| 268 | } else { |
| 269 | Ok(CachedValue::Hit(v)) |
| 270 | } |
| 271 | } |
| 272 | Err(e) => Err(e), |
| 273 | } |
| 274 | } |
| 275 | |
| 276 | fn evict(&self) { |
| 277 | if self.map.len() > self.capacity { |
no test coverage detected