@@ -54,6 +54,7 @@ use u32;
54
54
use u64;
55
55
use uint;
56
56
use vec;
57
+ use os:: getenv;
57
58
58
59
pub use self :: isaac:: { IsaacRng , Isaac64Rng } ;
59
60
pub use self :: os:: OSRng ;
@@ -284,15 +285,15 @@ pub trait Rng {
284
285
///
285
286
/// # Example
286
287
///
287
- /// ~~~{. rust}
288
+ /// ``` rust
288
289
/// use std::rand::{task_rng, Rng};
289
290
///
290
291
/// fn main() {
291
292
/// let mut v = [0u8, .. 13579];
292
293
/// task_rng().fill_bytes(v);
293
294
/// printfln!(v);
294
295
/// }
295
- /// ~~~
296
+ /// ```
296
297
fn fill_bytes ( & mut self , mut dest : & mut [ u8 ] ) {
297
298
// this relies on the lengths being transferred correctly when
298
299
// transmuting between vectors like this.
@@ -700,12 +701,16 @@ pub struct StdRng { priv rng: IsaacRng }
700
701
pub struct StdRng { priv rng: Isaac64Rng }
701
702
702
703
impl StdRng {
704
+ /// Create a randomly seeded instance of `StdRng`. This reads
705
+ /// randomness from the OS to seed the PRNG.
703
706
#[ cfg( not( target_word_size="64" ) ) ]
704
- fn new ( ) -> StdRng {
707
+ pub fn new ( ) -> StdRng {
705
708
StdRng { rng : IsaacRng :: new ( ) }
706
709
}
710
+ /// Create a randomly seeded instance of `StdRng`. This reads
711
+ /// randomness from the OS to seed the PRNG.
707
712
#[ cfg( target_word_size="64" ) ]
708
- fn new ( ) -> StdRng {
713
+ pub fn new ( ) -> StdRng {
709
714
StdRng { rng : Isaac64Rng :: new ( ) }
710
715
}
711
716
}
@@ -830,27 +835,96 @@ pub unsafe fn seed<T: Clone>(n: uint) -> ~[T] {
830
835
s
831
836
}
832
837
838
+ /// Controls how the task-local RNG is reseeded.
839
+ enum TaskRngReseeder {
840
+ /// Reseed using the StdRng::new() function, i.e. reading new
841
+ /// randomness.
842
+ WithNew ,
843
+ /// Don't reseed at all, e.g. when it has been explicitly seeded
844
+ /// by the user.
845
+ DontReseed
846
+ }
847
+
848
+ impl Default for TaskRngReseeder {
849
+ fn default ( ) -> TaskRngReseeder { WithNew }
850
+ }
851
+
852
+ impl reseeding:: Reseeder < StdRng > for TaskRngReseeder {
853
+ fn reseed ( & mut self , rng : & mut StdRng ) {
854
+ match * self {
855
+ WithNew => * rng = StdRng :: new ( ) ,
856
+ DontReseed => { }
857
+ }
858
+ }
859
+ }
860
+ static TASK_RNG_RESEED_THRESHOLD : uint = 32_768 ;
861
+ /// The task-local RNG.
862
+ pub type TaskRng = reseeding:: ReseedingRng < StdRng , TaskRngReseeder > ;
863
+
833
864
// used to make space in TLS for a random number generator
834
- local_data_key ! ( tls_rng_state : @mut StdRng )
865
+ local_data_key ! ( TASK_RNG_KEY : @mut TaskRng )
835
866
836
- /**
837
- * Gives back a lazily initialized task-local random number generator,
838
- * seeded by the system. Intended to be used in method chaining style, ie
839
- * `task_rng().gen::<int>()`.
840
- */
841
- #[ inline]
842
- pub fn task_rng ( ) -> @mut StdRng {
843
- let r = local_data:: get ( tls_rng_state, |k| k. map ( |& k| * k) ) ;
867
+ /// Retrieve the lazily-initialized task-local random number
868
+ /// generator, seeded by the system. Intended to be used in method
869
+ /// chaining style, e.g. `task_rng().gen::<int>()`.
870
+ ///
871
+ /// The RNG provided will reseed itself from the operating system
872
+ /// after generating a certain amount of randomness, unless it was
873
+ /// explicitly seeded either by `seed_task_rng` or by setting the
874
+ /// `RUST_SEED` environmental variable to some integer.
875
+ ///
876
+ /// The internal RNG used is platform and architecture dependent, so
877
+ /// may yield differing sequences on different computers, even when
878
+ /// explicitly seeded with `seed_task_rng`. If absolute consistency is
879
+ /// required, explicitly select an RNG, e.g. `IsaacRng` or
880
+ /// `Isaac64Rng`.
881
+ pub fn task_rng ( ) -> @mut TaskRng {
882
+ let r = local_data:: get ( TASK_RNG_KEY , |k| k. map ( |& k| * k) ) ;
844
883
match r {
845
884
None => {
846
- let rng = @mut StdRng :: new ( ) ;
847
- local_data:: set ( tls_rng_state, rng) ;
885
+ // check the environment
886
+ let ( sub_rng, reseeder) = match getenv ( "RUST_SEED" ) {
887
+ None => ( StdRng :: new ( ) , WithNew ) ,
888
+
889
+ Some ( s) => match from_str :: < uint > ( s) {
890
+ None => fail2 ! ( "`RUST_SEED` is `{}`, should be a positive integer." , s) ,
891
+ // explicitly seeded, so don't overwrite the seed later.
892
+ Some ( seed) => ( SeedableRng :: from_seed ( & [ seed] ) , DontReseed ) ,
893
+ }
894
+ } ;
895
+
896
+ let rng = @mut reseeding:: ReseedingRng :: new ( sub_rng,
897
+ TASK_RNG_RESEED_THRESHOLD ,
898
+ reseeder) ;
899
+ local_data:: set ( TASK_RNG_KEY , rng) ;
848
900
rng
849
901
}
850
902
Some ( rng) => rng
851
903
}
852
904
}
853
905
906
+ /// Explicitly seed (or reseed) the task-local random number
907
+ /// generator. This stops the RNG from automatically reseeding itself.
908
+ ///
909
+ /// # Example
910
+ ///
911
+ /// ```rust
912
+ /// use std::rand;
913
+ ///
914
+ /// fn main() {
915
+ /// rand::seed_task_rng(&[10u]);
916
+ /// printfln!("Same every time: %u", rand::random::<uint>());
917
+ ///
918
+ /// rand::seed_task_rng(&[1u, 2, 3, 4, 5, 6, 7, 8]);
919
+ /// printfln!("Same every time: %f", rand::random::<float>());
920
+ /// }
921
+ /// ```
922
+ pub fn seed_task_rng ( seed : & [ uint ] ) {
923
+ let t_r = task_rng ( ) ;
924
+ ( * t_r) . reseed ( seed) ;
925
+ t_r. reseeder = DontReseed ;
926
+ }
927
+
854
928
// Allow direct chaining with `task_rng`
855
929
impl < R : Rng > Rng for @mut R {
856
930
#[ inline]
@@ -863,10 +937,23 @@ impl<R: Rng> Rng for @mut R {
863
937
}
864
938
}
865
939
866
- /**
867
- * Returns a random value of a Rand type, using the task's random number
868
- * generator.
869
- */
940
+ /// Generate a random value using the task-local random number
941
+ /// generator.
942
+ ///
943
+ /// # Example
944
+ ///
945
+ /// ```rust
946
+ /// use std::rand::random;
947
+ ///
948
+ /// fn main() {
949
+ /// if random() {
950
+ /// let x = random();
951
+ /// printfln!(2u * x);
952
+ /// } else {
953
+ /// printfln!(random::<float>());
954
+ /// }
955
+ /// }
956
+ /// ```
870
957
#[ inline]
871
958
pub fn random < T : Rand > ( ) -> T {
872
959
task_rng ( ) . gen ( )
@@ -1053,6 +1140,16 @@ mod test {
1053
1140
* * e >= MIN_VAL && * * e <= MAX_VAL
1054
1141
} ) ) ;
1055
1142
}
1143
+
1144
+ #[ test]
1145
+ fn test_seed_task_rng ( ) {
1146
+ seed_task_rng ( [ 1 ] ) ;
1147
+ let first = random :: < uint > ( ) ;
1148
+
1149
+ seed_task_rng ( [ 1 ] ) ;
1150
+ let second = random :: < uint > ( ) ;
1151
+ assert_eq ! ( first, second) ;
1152
+ }
1056
1153
}
1057
1154
1058
1155
#[ cfg( test) ]
0 commit comments