cached/stores/
sized.rs

1use super::Cached;
2use crate::lru_list::LRUList;
3use hashbrown::raw::RawTable;
4use std::cmp::Eq;
5use std::fmt;
6use std::hash::{BuildHasher, Hash, Hasher};
7
8#[cfg(feature = "ahash")]
9use ahash::RandomState;
10
11#[cfg(not(feature = "ahash"))]
12use std::collections::hash_map::RandomState;
13
14#[cfg(feature = "async")]
15use {super::CachedAsync, async_trait::async_trait, futures::Future};
16
17/// Least Recently Used / `Sized` Cache
18///
19/// Stores up to a specified size before beginning
20/// to evict the least recently used keys
21///
22/// Note: This cache is in-memory only
23#[derive(Clone)]
24pub struct SizedCache<K, V> {
25    // `store` contains a hash of K -> index of (K, V) tuple in `order`
26    pub(super) store: RawTable<usize>,
27    pub(super) hash_builder: RandomState,
28    pub(super) order: LRUList<(K, V)>,
29    pub(super) capacity: usize,
30    pub(super) hits: u64,
31    pub(super) misses: u64,
32}
33
34impl<K, V> fmt::Debug for SizedCache<K, V>
35where
36    K: fmt::Debug,
37    V: fmt::Debug,
38{
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        f.debug_struct("SizedCache")
41            .field("order", &self.order)
42            .field("capacity", &self.capacity)
43            .field("hits", &self.hits)
44            .field("misses", &self.misses)
45            .finish()
46    }
47}
48
49impl<K, V> PartialEq for SizedCache<K, V>
50where
51    K: Eq + Hash + Clone,
52    V: PartialEq,
53{
54    fn eq(&self, other: &SizedCache<K, V>) -> bool {
55        self.store.len() == other.store.len() && {
56            self.order
57                .iter()
58                .all(|(key, value)| match other.get_index(other.hash(key), key) {
59                    Some(i) => value == &other.order.get(i).1,
60                    None => false,
61                })
62        }
63    }
64}
65
66impl<K, V> Eq for SizedCache<K, V>
67where
68    K: Eq + Hash + Clone,
69    V: PartialEq,
70{
71}
72
73impl<K: Hash + Eq + Clone, V> SizedCache<K, V> {
74    #[deprecated(since = "0.5.1", note = "method renamed to `with_size`")]
75    #[must_use]
76    pub fn with_capacity(size: usize) -> SizedCache<K, V> {
77        Self::with_size(size)
78    }
79
80    /// Creates a new `SizedCache` with a given size limit and pre-allocated backing data
81    ///
82    /// # Panics
83    ///
84    /// Will panic if size is 0
85    #[must_use]
86    pub fn with_size(size: usize) -> SizedCache<K, V> {
87        if size == 0 {
88            panic!("`size` of `SizedCache` must be greater than zero.");
89        }
90        SizedCache {
91            store: RawTable::with_capacity(size),
92            hash_builder: RandomState::new(),
93            order: LRUList::<(K, V)>::with_capacity(size),
94            capacity: size,
95            hits: 0,
96            misses: 0,
97        }
98    }
99
100    /// Creates a new `SizedCache` with a given size limit and pre-allocated backing data
101    ///
102    /// # Errors
103    ///
104    /// Will return a `std::io::Error`, depending on the error
105    pub fn try_with_size(size: usize) -> std::io::Result<SizedCache<K, V>> {
106        if size == 0 {
107            // EINVAL
108            return Err(std::io::Error::from_raw_os_error(22));
109        }
110
111        let store = match RawTable::try_with_capacity(size) {
112            Ok(store) => store,
113            Err(e) => {
114                let errcode = match e {
115                    // ENOMEM
116                    hashbrown::TryReserveError::AllocError { .. } => 12,
117                    // EINVAL
118                    hashbrown::TryReserveError::CapacityOverflow => 22,
119                };
120                return Err(std::io::Error::from_raw_os_error(errcode));
121            }
122        };
123
124        Ok(SizedCache {
125            store,
126            hash_builder: RandomState::new(),
127            order: LRUList::<(K, V)>::with_capacity(size),
128            capacity: size,
129            hits: 0,
130            misses: 0,
131        })
132    }
133
134    pub(super) fn iter_order(&self) -> impl Iterator<Item = &(K, V)> {
135        self.order.iter()
136    }
137
138    /// Return an iterator of keys in the current order from most
139    /// to least recently used.
140    pub fn key_order(&self) -> impl Iterator<Item = &K> {
141        self.order.iter().map(|(k, _v)| k)
142    }
143
144    /// Return an iterator of values in the current order from most
145    /// to least recently used.
146    pub fn value_order(&self) -> impl Iterator<Item = &V> {
147        self.order.iter().map(|(_k, v)| v)
148    }
149
150    fn hash<Q>(&self, key: &Q) -> u64
151    where
152        K: std::borrow::Borrow<Q>,
153        Q: std::hash::Hash + Eq + ?Sized,
154    {
155        let hasher = &mut self.hash_builder.build_hasher();
156        key.hash(hasher);
157        hasher.finish()
158    }
159
160    fn insert_index(&mut self, hash: u64, index: usize) {
161        let Self {
162            ref mut store,
163            ref order,
164            ref hash_builder,
165            ..
166        } = *self;
167        // insert the value `index` at `hash`, the closure provided
168        // is used to rehash values if a resize is necessary.
169        store.insert(hash, index, move |&i| {
170            // rehash the "key" value stored at index `i` - requires looking
171            // up the original "key" value in the `order` list.
172            let hasher = &mut hash_builder.build_hasher();
173            order.get(i).0.hash(hasher);
174            hasher.finish()
175        });
176    }
177
178    fn get_index<Q>(&self, hash: u64, key: &Q) -> Option<usize>
179    where
180        K: std::borrow::Borrow<Q>,
181        Q: std::hash::Hash + Eq + ?Sized,
182    {
183        let Self { store, order, .. } = self;
184        // Get the `order` index store under `hash`, the closure provided
185        // is used to compare against matching hashes - we lookup the original
186        // `key` value from the `order` list.
187        // This pattern is repeated in other lookup situations.
188        store
189            .get(hash, |&i| key == order.get(i).0.borrow())
190            .copied()
191    }
192
193    fn remove_index<Q>(&mut self, hash: u64, key: &Q) -> Option<usize>
194    where
195        K: std::borrow::Borrow<Q>,
196        Q: std::hash::Hash + Eq + ?Sized,
197    {
198        let Self { store, order, .. } = self;
199        store.remove_entry(hash, |&i| key == order.get(i).0.borrow())
200    }
201
202    fn check_capacity(&mut self) {
203        let Self {
204            ref mut store,
205            ref mut order,
206            ref hash_builder,
207            capacity,
208            ..
209        } = *self;
210        let len = store.len();
211        if len > capacity {
212            // store has reached capacity, evict the oldest item.
213            // store capacity cannot be zero, so there must be content in `self.order`.
214            let index = order.back();
215            let key = &order.get(index).0;
216            let hasher = &mut hash_builder.build_hasher();
217            key.hash(hasher);
218            let hash = hasher.finish();
219
220            let order_ = &order;
221            let erased = store.erase_entry(hash, |&i| *key == order_.get(i).0);
222            assert!(erased, "SizedCache::cache_set failed evicting cache key");
223            store.remove_entry(hash, |&i| *key == order_.get(i).0);
224            order.remove(index);
225        }
226    }
227
228    pub(super) fn get_if<F: FnOnce(&V) -> bool, Q>(&mut self, key: &Q, is_valid: F) -> Option<&V>
229    where
230        K: std::borrow::Borrow<Q>,
231        Q: std::hash::Hash + Eq + ?Sized,
232    {
233        if let Some(index) = self.get_index(self.hash(key), key) {
234            if is_valid(&self.order.get(index).1) {
235                self.order.move_to_front(index);
236                self.hits += 1;
237                return Some(&self.order.get(index).1);
238            }
239        }
240        self.misses += 1;
241        None
242    }
243
244    pub(super) fn get_mut_if<F: FnOnce(&V) -> bool, Q>(
245        &mut self,
246        key: &Q,
247        is_valid: F,
248    ) -> Option<&mut V>
249    where
250        K: std::borrow::Borrow<Q>,
251        Q: std::hash::Hash + Eq + ?Sized,
252    {
253        if let Some(index) = self.get_index(self.hash(key), key) {
254            if is_valid(&self.order.get(index).1) {
255                self.order.move_to_front(index);
256                self.hits += 1;
257                return Some(&mut self.order.get_mut(index).1);
258            }
259        }
260        self.misses += 1;
261        None
262    }
263
264    /// Get the cached value, or set it using `f` if the value
265    /// is either not-set or if `is_valid` returns `false` for
266    /// the set value.
267    ///
268    /// Returns (`was_present`, `was_valid`, mut ref to set value)
269    /// `was_valid` will be false when `was_present` is false
270    pub(super) fn get_or_set_with_if<F: FnOnce() -> V, FC: FnOnce(&V) -> bool>(
271        &mut self,
272        key: K,
273        f: F,
274        is_valid: FC,
275    ) -> (bool, bool, &mut V) {
276        let hash = self.hash(&key);
277        let index = self.get_index(hash, &key);
278        if let Some(index) = index {
279            self.hits += 1;
280            let replace_existing = {
281                let v = &self.order.get(index).1;
282                !is_valid(v)
283            };
284            if replace_existing {
285                self.order.set(index, (key, f()));
286            }
287            self.order.move_to_front(index);
288            (true, !replace_existing, &mut self.order.get_mut(index).1)
289        } else {
290            self.misses += 1;
291            let index = self.order.push_front((key, f()));
292            self.insert_index(hash, index);
293            self.check_capacity();
294            (false, false, &mut self.order.get_mut(index).1)
295        }
296    }
297
298    pub(super) fn try_get_or_set_with_if<E, F: FnOnce() -> Result<V, E>, FC: FnOnce(&V) -> bool>(
299        &mut self,
300        key: K,
301        f: F,
302        is_valid: FC,
303    ) -> Result<(bool, bool, &mut V), E> {
304        let hash = self.hash(&key);
305        let index = self.get_index(hash, &key);
306        if let Some(index) = index {
307            self.hits += 1;
308            let replace_existing = {
309                let v = &self.order.get(index).1;
310                !is_valid(v)
311            };
312            if replace_existing {
313                self.order.set(index, (key, f()?));
314            }
315            self.order.move_to_front(index);
316            Ok((true, !replace_existing, &mut self.order.get_mut(index).1))
317        } else {
318            self.misses += 1;
319            let index = self.order.push_front((key, f()?));
320            self.insert_index(hash, index);
321            self.check_capacity();
322            Ok((false, false, &mut self.order.get_mut(index).1))
323        }
324    }
325
326    /// Returns a reference to the cache's `order`
327    #[must_use]
328    pub fn get_order(&self) -> &LRUList<(K, V)> {
329        &self.order
330    }
331
332    pub fn retain<F: Fn(&K, &V) -> bool>(&mut self, keep: F) {
333        let remove_keys = self
334            .iter_order()
335            .filter_map(|(k, v)| if keep(k, v) { None } else { Some(k.clone()) })
336            .collect::<Vec<_>>();
337        for k in remove_keys {
338            self.cache_remove(&k);
339        }
340    }
341}
342
343#[cfg(feature = "async")]
344impl<K, V> SizedCache<K, V>
345where
346    K: Hash + Eq + Clone + Send,
347{
348    /// Get the cached value, or set it using `f` if the value
349    /// is either not-set or if `is_valid` returns `false` for
350    /// the set value.
351    ///
352    /// Returns (`was_present`, `was_valid`, mut ref to set value)
353    /// `was_valid` will be false when `was_present` is false
354    pub(super) async fn get_or_set_with_if_async<F, Fut, FC>(
355        &mut self,
356        key: K,
357        f: F,
358        is_valid: FC,
359    ) -> (bool, bool, &mut V)
360    where
361        V: Send,
362        F: FnOnce() -> Fut + Send,
363        Fut: Future<Output = V> + Send,
364        FC: FnOnce(&V) -> bool,
365    {
366        let hash = self.hash(&key);
367        let index = self.get_index(hash, &key);
368        if let Some(index) = index {
369            self.hits += 1;
370            let replace_existing = {
371                let v = &self.order.get(index).1;
372                !is_valid(v)
373            };
374            if replace_existing {
375                self.order.set(index, (key, f().await));
376            }
377            self.order.move_to_front(index);
378            (true, !replace_existing, &mut self.order.get_mut(index).1)
379        } else {
380            self.misses += 1;
381            let index = self.order.push_front((key, f().await));
382            self.insert_index(hash, index);
383            self.check_capacity();
384            (false, false, &mut self.order.get_mut(index).1)
385        }
386    }
387
388    pub(super) async fn try_get_or_set_with_if_async<E, F, Fut, FC>(
389        &mut self,
390        key: K,
391        f: F,
392        is_valid: FC,
393    ) -> Result<(bool, bool, &mut V), E>
394    where
395        V: Send,
396        F: FnOnce() -> Fut + Send,
397        Fut: Future<Output = Result<V, E>> + Send,
398        FC: FnOnce(&V) -> bool,
399    {
400        let hash = self.hash(&key);
401        let index = self.get_index(hash, &key);
402        if let Some(index) = index {
403            self.hits += 1;
404            let replace_existing = {
405                let v = &self.order.get(index).1;
406                !is_valid(v)
407            };
408            if replace_existing {
409                self.order.set(index, (key, f().await?));
410            }
411            self.order.move_to_front(index);
412            Ok((true, !replace_existing, &mut self.order.get_mut(index).1))
413        } else {
414            self.misses += 1;
415            let index = self.order.push_front((key, f().await?));
416            self.insert_index(hash, index);
417            self.check_capacity();
418            Ok((false, false, &mut self.order.get_mut(index).1))
419        }
420    }
421}
422
423impl<K: Hash + Eq + Clone, V> Cached<K, V> for SizedCache<K, V> {
424    fn cache_get<Q>(&mut self, key: &Q) -> Option<&V>
425    where
426        K: std::borrow::Borrow<Q>,
427        Q: std::hash::Hash + Eq + ?Sized,
428    {
429        self.get_if(key, |_| true)
430    }
431
432    fn cache_get_mut<Q>(&mut self, key: &Q) -> std::option::Option<&mut V>
433    where
434        K: std::borrow::Borrow<Q>,
435        Q: std::hash::Hash + Eq + ?Sized,
436    {
437        self.get_mut_if(key, |_| true)
438    }
439
440    fn cache_set(&mut self, key: K, val: V) -> Option<V> {
441        let hash = self.hash(&key);
442        let v = if let Some(index) = self.get_index(hash, &key) {
443            self.order.set(index, (key, val)).map(|(_, v)| v)
444        } else {
445            let index = self.order.push_front((key, val));
446            self.insert_index(hash, index);
447            None
448        };
449        self.check_capacity();
450        v
451    }
452
453    fn cache_get_or_set_with<F: FnOnce() -> V>(&mut self, key: K, f: F) -> &mut V {
454        let (_, _, v) = self.get_or_set_with_if(key, f, |_| true);
455        v
456    }
457
458    fn cache_try_get_or_set_with<F: FnOnce() -> Result<V, E>, E>(
459        &mut self,
460        k: K,
461        f: F,
462    ) -> Result<&mut V, E> {
463        let (_, _, v) = self.try_get_or_set_with_if(k, f, |_| true)?;
464        Ok(v)
465    }
466
467    fn cache_remove<Q>(&mut self, k: &Q) -> Option<V>
468    where
469        K: std::borrow::Borrow<Q>,
470        Q: std::hash::Hash + Eq + ?Sized,
471    {
472        // try and remove item from mapping, and then from order list if it was in mapping
473        let hash = self.hash(k);
474        if let Some(index) = self.remove_index(hash, k) {
475            // need to remove the key in the order list
476            let (_key, value) = self.order.remove(index);
477            Some(value)
478        } else {
479            None
480        }
481    }
482    fn cache_clear(&mut self) {
483        // clear both the store and the order list
484        self.store.clear();
485        self.order.clear();
486    }
487    fn cache_reset(&mut self) {
488        // SizedCache uses cache_clear because capacity is fixed.
489        self.cache_clear();
490    }
491    fn cache_reset_metrics(&mut self) {
492        self.misses = 0;
493        self.hits = 0;
494    }
495    fn cache_size(&self) -> usize {
496        self.store.len()
497    }
498    fn cache_hits(&self) -> Option<u64> {
499        Some(self.hits)
500    }
501    fn cache_misses(&self) -> Option<u64> {
502        Some(self.misses)
503    }
504    fn cache_capacity(&self) -> Option<usize> {
505        Some(self.capacity)
506    }
507}
508
509#[cfg(feature = "async")]
510#[async_trait]
511impl<K, V> CachedAsync<K, V> for SizedCache<K, V>
512where
513    K: Hash + Eq + Clone + Send,
514{
515    async fn get_or_set_with<F, Fut>(&mut self, k: K, f: F) -> &mut V
516    where
517        V: Send,
518        F: FnOnce() -> Fut + Send,
519        Fut: Future<Output = V> + Send,
520    {
521        let (_, _, v) = self.get_or_set_with_if_async(k, f, |_| true).await;
522        v
523    }
524
525    async fn try_get_or_set_with<F, Fut, E>(&mut self, k: K, f: F) -> Result<&mut V, E>
526    where
527        V: Send,
528        F: FnOnce() -> Fut + Send,
529        Fut: Future<Output = Result<V, E>> + Send,
530    {
531        let (_, _, v) = self.try_get_or_set_with_if_async(k, f, |_| true).await?;
532        Ok(v)
533    }
534}
535
536#[cfg(test)]
537/// Cache store tests
538mod tests {
539    use super::*;
540
541    #[test]
542    fn sized_cache() {
543        let mut c = SizedCache::with_size(5);
544        assert!(c.cache_get(&1).is_none());
545        let misses = c.cache_misses().unwrap();
546        assert_eq!(1, misses);
547
548        assert_eq!(c.cache_set(1, 100), None);
549        assert!(c.cache_get(&1).is_some());
550        let hits = c.cache_hits().unwrap();
551        let misses = c.cache_misses().unwrap();
552        assert_eq!(1, hits);
553        assert_eq!(1, misses);
554
555        assert_eq!(c.cache_set(2, 100), None);
556        assert_eq!(c.cache_set(3, 100), None);
557        assert_eq!(c.cache_set(4, 100), None);
558        assert_eq!(c.cache_set(5, 100), None);
559
560        assert_eq!(c.key_order().copied().collect::<Vec<_>>(), [5, 4, 3, 2, 1]);
561
562        assert_eq!(c.cache_set(6, 100), None);
563        assert_eq!(c.cache_set(7, 100), None);
564
565        assert_eq!(c.key_order().copied().collect::<Vec<_>>(), [7, 6, 5, 4, 3]);
566
567        assert!(c.cache_get(&2).is_none());
568        assert!(c.cache_get(&3).is_some());
569
570        assert_eq!(c.key_order().copied().collect::<Vec<_>>(), [3, 7, 6, 5, 4]);
571
572        assert_eq!(2, c.cache_misses().unwrap());
573        let size = c.cache_size();
574        assert_eq!(5, size);
575
576        c.cache_reset_metrics();
577        let hits = c.cache_hits().unwrap();
578        let misses = c.cache_misses().unwrap();
579        let size = c.cache_size();
580        assert_eq!(0, hits);
581        assert_eq!(0, misses);
582        assert_eq!(5, size);
583
584        assert_eq!(c.cache_set(7, 200), Some(100));
585
586        #[derive(Hash, Clone, Eq, PartialEq)]
587        struct MyKey {
588            v: String,
589        }
590        let mut c = SizedCache::with_size(5);
591        assert_eq!(
592            c.cache_set(
593                MyKey {
594                    v: String::from("s")
595                },
596                String::from("a")
597            ),
598            None
599        );
600        assert_eq!(
601            c.cache_set(
602                MyKey {
603                    v: String::from("s")
604                },
605                String::from("a")
606            ),
607            Some(String::from("a"))
608        );
609        assert_eq!(
610            c.cache_set(
611                MyKey {
612                    v: String::from("s2")
613                },
614                String::from("b")
615            ),
616            None
617        );
618        assert_eq!(
619            c.cache_set(
620                MyKey {
621                    v: String::from("s2")
622                },
623                String::from("b")
624            ),
625            Some(String::from("b"))
626        );
627    }
628
629    #[test]
630    fn try_new() {
631        let c: std::io::Result<SizedCache<i32, i32>> = SizedCache::try_with_size(0);
632        assert_eq!(c.unwrap_err().raw_os_error(), Some(22));
633    }
634
635    #[test]
636    /// This is a regression test to confirm that racing cache sets on a `SizedCache`
637    /// do not cause duplicates to exist in the internal `order`. See issue #7
638    fn size_cache_racing_keys_eviction_regression() {
639        let mut c = SizedCache::with_size(2);
640        assert_eq!(c.cache_set(1, 100), None);
641        assert_eq!(c.cache_set(1, 100), Some(100));
642        // size would be 1, but internal ordered would be [1, 1]
643        assert_eq!(c.cache_set(2, 100), None);
644        assert_eq!(c.cache_set(3, 100), None);
645        // this next set would fail because a duplicate key would be evicted
646        assert_eq!(c.cache_set(4, 100), None);
647    }
648
649    #[test]
650    fn clear() {
651        let mut c = SizedCache::with_size(3);
652
653        assert_eq!(c.cache_set(1, 100), None);
654        assert_eq!(c.cache_set(2, 200), None);
655        assert_eq!(c.cache_set(3, 300), None);
656        c.cache_clear();
657
658        assert_eq!(0, c.cache_size());
659    }
660
661    #[test]
662    fn reset() {
663        let init_capacity = 1;
664        let mut c = SizedCache::with_size(init_capacity);
665        assert_eq!(c.cache_set(1, 100), None);
666        assert_eq!(c.cache_set(2, 200), None);
667        assert_eq!(c.cache_set(3, 300), None);
668        assert!(init_capacity <= c.store.capacity());
669
670        c.cache_reset();
671
672        assert!(init_capacity <= c.store.capacity());
673    }
674
675    #[test]
676    fn remove() {
677        let mut c = SizedCache::with_size(3);
678
679        assert_eq!(c.cache_set(1, 100), None);
680        assert_eq!(c.cache_set(2, 200), None);
681        assert_eq!(c.cache_set(3, 300), None);
682
683        assert_eq!(Some(100), c.cache_remove(&1));
684        assert_eq!(2, c.cache_size());
685
686        assert_eq!(Some(200), c.cache_remove(&2));
687        assert_eq!(1, c.cache_size());
688
689        assert_eq!(None, c.cache_remove(&2));
690        assert_eq!(1, c.cache_size());
691
692        assert_eq!(Some(300), c.cache_remove(&3));
693        assert_eq!(0, c.cache_size());
694    }
695
696    #[test]
697    fn sized_cache_get_mut() {
698        let mut c = SizedCache::with_size(5);
699        assert!(c.cache_get_mut(&1).is_none());
700        let misses = c.cache_misses().unwrap();
701        assert_eq!(1, misses);
702
703        assert_eq!(c.cache_set(1, 100), None);
704        assert_eq!(*c.cache_get_mut(&1).unwrap(), 100);
705        let hits = c.cache_hits().unwrap();
706        let misses = c.cache_misses().unwrap();
707        assert_eq!(1, hits);
708        assert_eq!(1, misses);
709
710        let value = c.cache_get_mut(&1).unwrap();
711        *value = 10;
712
713        let hits = c.cache_hits().unwrap();
714        let misses = c.cache_misses().unwrap();
715        assert_eq!(2, hits);
716        assert_eq!(1, misses);
717        assert_eq!(*c.cache_get_mut(&1).unwrap(), 10);
718    }
719
720    #[test]
721    fn sized_cache_eviction_fix() {
722        let mut cache = SizedCache::<u32, ()>::with_size(3);
723
724        cache.cache_set(1, ());
725        cache.cache_set(2, ());
726        cache.cache_set(3, ());
727
728        assert!(cache.cache_get(&1).is_some());
729        assert!(cache.cache_get(&2).is_some());
730        assert!(cache.cache_get(&3).is_some());
731        assert!(cache.cache_get(&4).is_none());
732
733        // previous bug: inserting the same key multiple times would continue
734        //               to evict the oldest cache member
735        cache.cache_set(4, ());
736        assert_eq!(cache.cache_size(), 3);
737        cache.cache_set(4, ());
738        assert_eq!(cache.cache_size(), 3); // previously failed, returning 2
739
740        assert!(cache.cache_get(&1).is_none()); // 1 is evicted by first "4" insert
741        assert!(cache.cache_get(&2).is_some()); // previously failed, 2 would be evicted by second "4" insert
742        assert!(cache.cache_get(&3).is_some());
743        assert!(cache.cache_get(&4).is_some());
744    }
745
746    #[test]
747    fn get_or_set_with() {
748        let mut c = SizedCache::with_size(5);
749
750        assert_eq!(c.cache_get_or_set_with(0, || 0), &0);
751        assert_eq!(c.cache_get_or_set_with(1, || 1), &1);
752        assert_eq!(c.cache_get_or_set_with(2, || 2), &2);
753        assert_eq!(c.cache_get_or_set_with(3, || 3), &3);
754        assert_eq!(c.cache_get_or_set_with(4, || 4), &4);
755        assert_eq!(c.cache_get_or_set_with(5, || 5), &5);
756
757        assert_eq!(c.cache_misses(), Some(6));
758
759        assert_eq!(c.cache_get_or_set_with(0, || 0), &0);
760
761        assert_eq!(c.cache_misses(), Some(7));
762
763        assert_eq!(c.cache_get_or_set_with(0, || 42), &0);
764
765        assert_eq!(c.cache_misses(), Some(7));
766
767        assert_eq!(c.cache_get_or_set_with(1, || 1), &1);
768
769        assert_eq!(c.cache_misses(), Some(8));
770
771        c.cache_reset();
772        fn _try_get(n: usize) -> Result<usize, String> {
773            if n < 10 {
774                Ok(n)
775            } else {
776                Err("dead".to_string())
777            }
778        }
779        let res: Result<&mut usize, String> = c.cache_try_get_or_set_with(0, || _try_get(10));
780        assert!(res.is_err());
781        assert!(c.key_order().next().is_none());
782
783        let res: Result<&mut usize, String> = c.cache_try_get_or_set_with(0, || _try_get(1));
784        assert_eq!(res.unwrap(), &1);
785        let res: Result<&mut usize, String> = c.cache_try_get_or_set_with(0, || _try_get(5));
786        assert_eq!(res.unwrap(), &1);
787    }
788
789    #[cfg(feature = "async")]
790    #[tokio::test]
791    async fn test_async_trait() {
792        use crate::CachedAsync;
793        let mut c = SizedCache::with_size(5);
794
795        async fn _get(n: usize) -> usize {
796            n
797        }
798
799        assert_eq!(c.get_or_set_with(0, || async { _get(0).await }).await, &0);
800        assert_eq!(c.get_or_set_with(1, || async { _get(1).await }).await, &1);
801        assert_eq!(c.get_or_set_with(2, || async { _get(2).await }).await, &2);
802        assert_eq!(c.get_or_set_with(3, || async { _get(3).await }).await, &3);
803
804        assert_eq!(c.get_or_set_with(0, || async { _get(3).await }).await, &0);
805        assert_eq!(c.get_or_set_with(1, || async { _get(3).await }).await, &1);
806        assert_eq!(c.get_or_set_with(2, || async { _get(3).await }).await, &2);
807        assert_eq!(c.get_or_set_with(3, || async { _get(1).await }).await, &3);
808
809        c.cache_reset();
810        async fn _try_get(n: usize) -> Result<usize, String> {
811            if n < 10 {
812                Ok(n)
813            } else {
814                Err("dead".to_string())
815            }
816        }
817
818        assert_eq!(
819            c.try_get_or_set_with(0, || async {
820                match _try_get(0).await {
821                    Ok(n) => Ok(n),
822                    Err(_) => Err("err".to_string()),
823                }
824            })
825            .await
826            .unwrap(),
827            &0
828        );
829        assert_eq!(
830            c.try_get_or_set_with(0, || async {
831                match _try_get(5).await {
832                    Ok(n) => Ok(n),
833                    Err(_) => Err("err".to_string()),
834                }
835            })
836            .await
837            .unwrap(),
838            &0
839        );
840
841        c.cache_reset();
842        let res: Result<&mut usize, String> = c
843            .try_get_or_set_with(0, || async { _try_get(10).await })
844            .await;
845        assert!(res.is_err());
846        assert!(c.key_order().next().is_none());
847
848        let res: Result<&mut usize, String> = c
849            .try_get_or_set_with(0, || async { _try_get(1).await })
850            .await;
851        assert_eq!(res.unwrap(), &1);
852        let res: Result<&mut usize, String> = c
853            .try_get_or_set_with(0, || async { _try_get(5).await })
854            .await;
855        assert_eq!(res.unwrap(), &1);
856    }
857}