1
1
use crate :: io;
2
+ use crate :: lazy;
2
3
use crate :: mem;
3
- use crate :: sync;
4
4
use crate :: sys:: c;
5
5
6
- // The kinds of HashMap RNG that may be available
6
+ /// The kinds of HashMap RNG that may be available
7
7
#[ derive( Clone , Copy , Debug , PartialEq ) ]
8
8
enum HashMapRng {
9
9
Preferred ,
@@ -16,44 +16,35 @@ pub fn hashmap_random_keys() -> (u64, u64) {
16
16
preferred_rng ( ) . expect ( "couldn't generate random bytes with preferred RNG" )
17
17
}
18
18
HashMapRng :: Fallback => {
19
- fallback_rng ( ) . unwrap ( ) . expect ( "couldn't generate random bytes with fallback RNG" )
19
+ fallback_rng ( ) . expect ( "couldn't generate random bytes with fallback RNG" )
20
20
}
21
21
}
22
22
}
23
23
24
- // Returns the HashMap RNG that should be used
25
- //
26
- // Panics if they are both broken
24
+ /// Returns the HashMap RNG that should be used
25
+ ///
26
+ /// Panics if they are both broken
27
27
fn get_hashmap_rng ( ) -> HashMapRng {
28
28
// Assume that if the preferred RNG is broken the first time we use it, it likely means
29
29
// that: the DLL has failed to load, there is no point to calling it over-and-over again,
30
30
// and we should cache the result
31
- static INIT : sync:: Once = sync:: Once :: new ( ) ;
32
- static mut HASHMAP_RNG : HashMapRng = HashMapRng :: Preferred ;
33
-
34
- unsafe {
35
- INIT . call_once ( || HASHMAP_RNG = choose_hashmap_rng ( ) ) ;
36
- HASHMAP_RNG
37
- }
31
+ static VALUE : lazy:: SyncOnceCell < HashMapRng > = lazy:: SyncOnceCell :: new ( ) ;
32
+ * VALUE . get_or_init ( choose_hashmap_rng)
38
33
}
39
34
40
- // Test whether we should use the preferred or fallback RNG
41
- //
42
- // If the preferred RNG is successful, we choose it. Otherwise, if the fallback RNG is successful,
43
- // we choose that
44
- //
45
- // Panics if both the preferred and the fallback RNG are both non-functional
35
+ /// Test whether we should use the preferred or fallback RNG
36
+ ///
37
+ /// If the preferred RNG is successful, we choose it. Otherwise, if the fallback RNG is successful,
38
+ /// we choose that
39
+ ///
40
+ /// Panics if both the preferred and the fallback RNG are both non-functional
46
41
fn choose_hashmap_rng ( ) -> HashMapRng {
47
42
let preferred_error = match preferred_rng ( ) {
48
43
Ok ( _) => return HashMapRng :: Preferred ,
49
44
Err ( e) => e,
50
45
} ;
51
46
52
- // On UWP, there is no fallback
53
- let fallback_result = fallback_rng ( )
54
- . unwrap_or_else ( || panic ! ( "preferred RNG broken: `{}`, no fallback" , preferred_error) ) ;
55
-
56
- match fallback_result {
47
+ match fallback_rng ( ) {
57
48
Ok ( _) => return HashMapRng :: Fallback ,
58
49
Err ( fallback_error) => panic ! (
59
50
"preferred RNG broken: `{}`, fallback RNG broken: `{}`" ,
@@ -62,7 +53,7 @@ fn choose_hashmap_rng() -> HashMapRng {
62
53
}
63
54
}
64
55
65
- // Generate random numbers using the preferred RNG function (BCryptGenRandom)
56
+ /// Generate random numbers using the preferred RNG function (BCryptGenRandom)
66
57
fn preferred_rng ( ) -> Result < ( u64 , u64 ) , io:: Error > {
67
58
use crate :: ptr;
68
59
@@ -79,18 +70,18 @@ fn preferred_rng() -> Result<(u64, u64), io::Error> {
79
70
if ret == 0 { Ok ( v) } else { Err ( io:: Error :: last_os_error ( ) ) }
80
71
}
81
72
82
- // Generate random numbers using the fallback RNG function (RtlGenRandom)
73
+ /// Generate random numbers using the fallback RNG function (RtlGenRandom)
83
74
#[ cfg( not( target_vendor = "uwp" ) ) ]
84
- fn fallback_rng ( ) -> Option < Result < ( u64 , u64 ) , io:: Error > > {
75
+ fn fallback_rng ( ) -> Result < ( u64 , u64 ) , io:: Error > {
85
76
let mut v = ( 0 , 0 ) ;
86
77
let ret =
87
78
unsafe { c:: RtlGenRandom ( & mut v as * mut _ as * mut u8 , mem:: size_of_val ( & v) as c:: ULONG ) } ;
88
79
89
- Some ( if ret != 0 { Ok ( v) } else { Err ( io:: Error :: last_os_error ( ) ) } )
80
+ if ret != 0 { Ok ( v) } else { Err ( io:: Error :: last_os_error ( ) ) }
90
81
}
91
82
92
- // We can't use RtlGenRandom with UWP, so there is no fallback
83
+ /// We can't use RtlGenRandom with UWP, so there is no fallback
93
84
#[ cfg( target_vendor = "uwp" ) ]
94
- fn fallback_rng ( ) -> Option < Result < ( u64 , u64 ) , io:: Error > > {
95
- None
85
+ fn fallback_rng ( ) -> Result < ( u64 , u64 ) , io:: Error > {
86
+ Err ( io :: const_io_error! ( io :: ErrorKind :: Unsupported , "unsupported on UWP" ) )
96
87
}
0 commit comments