@@ -13,77 +13,35 @@ use std::fmt;
13
13
use std:: rc:: Rc ;
14
14
use std:: thread_local;
15
15
16
- use rand_chacha:: ChaCha12Rng ;
17
- use rand_core:: SeedableRng ;
18
-
19
16
pub use rand_core:: { self , CryptoRng , RngCore } ;
20
17
21
- // Rationale for using `UnsafeCell` in `ThreadRng`:
22
- //
23
- // Previously we used a `RefCell`, with an overhead of ~15%. There will only
24
- // ever be one mutable reference to the interior of the `UnsafeCell`, because
25
- // we only have such a reference inside `next_u32`, `next_u64`, etc. Within a
26
- // single thread (which is the definition of `ThreadRng`), there will only ever
27
- // be one of these methods active at a time.
28
- //
29
- // A possible scenario where there could be multiple mutable references is if
30
- // `ThreadRng` is used inside `next_u32` and co. But the implementation is
31
- // completely under our control. We just have to ensure none of them use
32
- // `ThreadRng` internally, which is nonsensical anyway. We should also never run
33
- // `ThreadRng` in destructors of its implementation, which is also nonsensical.
34
-
35
- // Number of generated bytes after which to reseed `ThreadRng`.
36
- // According to benchmarks, reseeding has a noticeable impact with thresholds
37
- // of 32 kB and less. We choose 64 kB to avoid significant overhead.
38
- const THREAD_RNG_RESEED_THRESHOLD : isize = 1024 * 64 ;
39
-
40
- struct ReseedingRng {
41
- rng : ChaCha12Rng ,
42
- bytes_until_reseed : isize ,
43
- }
18
+ mod reseeding_rng;
19
+ use reseeding_rng:: ReseedingRng ;
44
20
45
- impl ReseedingRng {
46
- #[ inline( always) ]
47
- fn reseed_check ( & mut self , n : isize ) {
48
- if self . bytes_until_reseed < 0 {
49
- // If system RNG has failed for some reason, ignore the error
50
- // and continue to work with the old RNG state.
51
- let _ = self . reseed ( ) ;
21
+ thread_local ! (
22
+ // We require Rc<..> to avoid premature freeing when ThreadRng is used
23
+ // within thread-local destructors. See https://github.com/rust-random/rand/issues/968.
24
+ //
25
+ // Rationale for using `UnsafeCell`:
26
+ //
27
+ // Previously we used a `RefCell`, with an overhead of ~15%. There will only
28
+ // ever be one mutable reference to the interior of the `UnsafeCell`, because
29
+ // we only have such a reference inside `next_u32`, `next_u64`, etc. Within a
30
+ // single thread (which is the definition of `ThreadRng`), there will only ever
31
+ // be one of these methods active at a time.
32
+ //
33
+ // A possible scenario where there could be multiple mutable references is if
34
+ // `ThreadRng` is used inside `next_u32` and co. But the implementation is
35
+ // completely under our control. We just have to ensure none of them use
36
+ // `ThreadRng` internally, which is nonsensical anyway. We should also never run
37
+ // `ThreadRng` in destructors of its implementation, which is also nonsensical.
38
+ static THREAD_RNG_KEY : Rc <UnsafeCell <ReseedingRng >> = {
39
+ match ReseedingRng :: new( ) {
40
+ Ok ( rng) => Rc :: new( UnsafeCell :: new( rng) ) ,
41
+ Err ( err) => panic!( "could not initialize ThreadRng: {}" , err) ,
52
42
}
53
- self . bytes_until_reseed -= n;
54
- }
55
-
56
- #[ inline( always) ]
57
- fn reseed ( & mut self ) -> Result < ( ) , rand_core:: getrandom:: Error > {
58
- self . bytes_until_reseed = THREAD_RNG_RESEED_THRESHOLD ;
59
- self . rng = ChaCha12Rng :: try_from_os_rng ( ) ?;
60
- Ok ( ( ) )
61
- }
62
- }
63
-
64
- impl RngCore for ReseedingRng {
65
- #[ inline( always) ]
66
- fn next_u32 ( & mut self ) -> u32 {
67
- self . reseed_check ( core:: mem:: size_of :: < u32 > ( ) as isize ) ;
68
- self . rng . next_u32 ( )
69
43
}
70
-
71
- #[ inline( always) ]
72
- fn next_u64 ( & mut self ) -> u64 {
73
- self . reseed_check ( core:: mem:: size_of :: < u64 > ( ) as isize ) ;
74
- self . rng . next_u64 ( )
75
- }
76
-
77
- #[ inline( always) ]
78
- fn fill_bytes ( & mut self , dest : & mut [ u8 ] ) {
79
- // Valid allocation can not be bigger than `isize::MAX` bytes,
80
- // so we can cast length to `isize` without issues.
81
- self . reseed_check ( dest. len ( ) as isize ) ;
82
- self . rng . fill_bytes ( dest)
83
- }
84
- }
85
-
86
- impl CryptoRng for ReseedingRng { }
44
+ ) ;
87
45
88
46
/// A reference to the thread-local generator.
89
47
///
@@ -165,17 +123,6 @@ impl fmt::Debug for ThreadRng {
165
123
}
166
124
}
167
125
168
- thread_local ! (
169
- // We require Rc<..> to avoid premature freeing when ThreadRng is used
170
- // within thread-local destructors. See https://github.com/rust-random/rand/issues/968.
171
- static THREAD_RNG_KEY : Rc <UnsafeCell <ReseedingRng >> = {
172
- let rng = ChaCha12Rng :: try_from_os_rng( ) . unwrap_or_else( |err|
173
- panic!( "could not initialize ThreadRng: {}" , err) ) ;
174
- let reseeding_rng = ReseedingRng { rng, bytes_until_reseed: THREAD_RNG_RESEED_THRESHOLD } ;
175
- Rc :: new( UnsafeCell :: new( reseeding_rng) )
176
- }
177
- ) ;
178
-
179
126
/// Access a fast, pre-initialized generator
180
127
///
181
128
/// This is a handle to the local [`ThreadRng`].
0 commit comments