@@ -508,6 +508,61 @@ impl<K: Hash + Eq, V, S: BuildHasher> LruCache<K, V, S> {
508
508
}
509
509
}
510
510
511
+ /// Returns a reference to the value of the key in the cache if it is
512
+ /// present in the cache and moves the key to the head of the LRU list.
513
+ /// If the key does not exist the provided `FnOnce` is used to populate
514
+ /// the list and a reference is returned. If `FnOnce` returns `Err`,
515
+ /// returns the `Err`.
516
+ ///
517
+ /// # Example
518
+ ///
519
+ /// ```
520
+ /// use lru::LruCache;
521
+ /// use std::num::NonZeroUsize;
522
+ /// let mut cache = LruCache::new(NonZeroUsize::new(2).unwrap());
523
+ ///
524
+ /// cache.put(1, "a");
525
+ /// cache.put(2, "b");
526
+ /// cache.put(2, "c");
527
+ /// cache.put(3, "d");
528
+ ///
529
+ /// let f = ||->Result<&str, String> {Err("failed".to_owned())};
530
+ /// let a = ||->Result<&str, String> {Ok("a")};
531
+ /// let b = ||->Result<&str, String> {Ok("b")};
532
+ /// assert_eq!(cache.try_get_or_insert(2, a), Ok(&"c"));
533
+ /// assert_eq!(cache.try_get_or_insert(3, a), Ok(&"d"));
534
+ /// assert_eq!(cache.try_get_or_insert(1, f), Err("failed".to_owned()));
535
+ /// assert_eq!(cache.try_get_or_insert(1, b), Ok(&"b"));
536
+ /// assert_eq!(cache.try_get_or_insert(1, a), Ok(&"b"));
537
+ /// ```
538
+ pub fn try_get_or_insert < F , E > ( & mut self , k : K , f : F ) -> Result < & V , E >
539
+ where
540
+ F : FnOnce ( ) -> Result < V , E > ,
541
+ {
542
+ if let Some ( node) = self . map . get_mut ( & KeyRef { k : & k } ) {
543
+ let node_ptr: * mut LruEntry < K , V > = node. as_ptr ( ) ;
544
+
545
+ self . detach ( node_ptr) ;
546
+ self . attach ( node_ptr) ;
547
+
548
+ unsafe { Ok ( & * ( * node_ptr) . val . as_ptr ( ) ) }
549
+ } else {
550
+ match f ( ) {
551
+ Err ( e) => Err ( e) ,
552
+ Ok ( v) => {
553
+ let ( _, node) = self . replace_or_create_node ( k, v) ;
554
+ let node_ptr: * mut LruEntry < K , V > = node. as_ptr ( ) ;
555
+
556
+ self . attach ( node_ptr) ;
557
+
558
+ let keyref = unsafe { ( * node_ptr) . key . as_ptr ( ) } ;
559
+ self . map . insert ( KeyRef { k : keyref } , node) ;
560
+ Ok ( unsafe { & * ( * node_ptr) . val . as_ptr ( ) } )
561
+ }
562
+ }
563
+ }
564
+ }
565
+
511
566
/// Returns a mutable reference to the value of the key in the cache if it is
512
567
/// present in the cache and moves the key to the head of the LRU list.
513
568
/// If the key does not exist the provided `FnOnce` is used to populate
@@ -1392,6 +1447,17 @@ mod tests {
1392
1447
assert_eq ! ( cache. get_or_insert( "lemon" , || "red" ) , & "orange" ) ;
1393
1448
}
1394
1449
1450
+ #[ test]
1451
+ fn test_try_get_or_insert ( ) {
1452
+ let mut cache = LruCache :: new ( NonZeroUsize :: new ( 2 ) . unwrap ( ) ) ;
1453
+
1454
+ assert_eq ! ( cache. try_get_or_insert:: <_, & str >( "apple" , || Ok ( "red" ) ) , Ok ( & "red" ) ) ;
1455
+ assert_eq ! ( cache. try_get_or_insert:: <_, & str >( "apple" , || Err ( "failed" ) ) , Ok ( & "red" ) ) ;
1456
+ assert_eq ! ( cache. try_get_or_insert:: <_, & str >( "banana" , || Ok ( "orange" ) ) , Ok ( & "orange" ) ) ;
1457
+ assert_eq ! ( cache. try_get_or_insert:: <_, & str >( "lemon" , || Err ( "failed" ) ) , Err ( "failed" ) ) ;
1458
+ assert_eq ! ( cache. try_get_or_insert:: <_, & str >( "banana" , || Err ( "failed" ) ) , Ok ( & "orange" ) ) ;
1459
+ }
1460
+
1395
1461
#[ test]
1396
1462
fn test_put_and_get_or_insert_mut ( ) {
1397
1463
let mut cache = LruCache :: new ( NonZeroUsize :: new ( 2 ) . unwrap ( ) ) ;
0 commit comments