1
1
use std:: cell:: { Cell , OnceCell } ;
2
2
3
- pub struct Cached < T > {
4
- init : Cell < Option < Box < dyn FnOnce ( ) -> T > > > ,
3
+ pub struct Cached < ' a , T > {
4
+ init : Cell < Option < Box < dyn FnOnce ( ) -> T + ' a > > > ,
5
5
value : OnceCell < T > ,
6
6
}
7
7
8
- impl < T > Cached < T > {
9
- pub fn new ( init : impl FnOnce ( ) -> T + ' static ) -> Self {
8
+ impl < ' a , T > Cached < ' a , T > {
9
+ pub fn new ( init : impl FnOnce ( ) -> T + ' a ) -> Self {
10
10
Self {
11
11
init : Cell :: new ( Some ( Box :: new ( init) ) ) ,
12
12
value : OnceCell :: new ( ) ,
@@ -16,36 +16,36 @@ impl<T> Cached<T> {
16
16
pub fn get ( & self ) -> & T {
17
17
self . value . get_or_init ( || {
18
18
let Some ( init) = self . init . take ( ) else {
19
- panic ! ( "[bug] init function called twice!" )
19
+ unreachable ! ( "The init function should be never called twice" ) ;
20
20
} ;
21
21
init ( )
22
22
} )
23
23
}
24
+
25
+ pub fn take ( self ) -> T {
26
+ let _ = self . get ( ) ;
27
+ let Some ( value) = self . value . into_inner ( ) else {
28
+ unreachable ! ( "The value should be always cached after calling get()" ) ;
29
+ } ;
30
+ value
31
+ }
24
32
}
25
33
26
34
#[ cfg( test) ]
27
35
mod tests {
28
36
use super :: * ;
29
37
30
- #[ derive( Debug ) ]
31
- struct Foo {
32
- #[ allow( dead_code) ]
33
- message : String ,
34
- }
35
-
36
- impl Drop for Foo {
37
- fn drop ( & mut self ) {
38
- println ! ( "Dropped: {self:?}" )
39
- }
40
- }
41
-
42
38
#[ test]
43
- fn test ( ) {
44
- let msg = "hello" . to_owned ( ) ;
45
- let c1 = Cached :: new ( || Foo { message : msg } ) ;
46
- let msg2 = "hello" . to_owned ( ) ;
47
- let _c2 = Cached :: new ( || Foo { message : msg2 } ) ;
48
- println ! ( "{:?} world" , c1. get( ) ) ;
49
- println ! ( "{:?} world again" , c1. get( ) ) ;
39
+ fn test_cached ( ) {
40
+ let mut n_called = 0 ;
41
+ let cached = Cached :: new ( || {
42
+ n_called += 1 ;
43
+ "hello" . to_string ( )
44
+ } ) ;
45
+ assert_eq ! ( cached. get( ) , "hello" ) ;
46
+ assert_eq ! ( cached. get( ) , "hello" ) ;
47
+ assert_eq ! ( cached. get( ) , "hello" ) ;
48
+ drop ( cached) ;
49
+ assert_eq ! ( n_called, 1 ) ;
50
50
}
51
51
}
0 commit comments