1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-25 16:49:18 -05:00

Add --seed for setting RNG seed (#2483)

This commit is contained in:
Matt Harrison 2019-06-11 15:34:39 +01:00 committed by Ryan Dahl
parent cb58162052
commit d82c1991cf
7 changed files with 112 additions and 2 deletions

View file

@ -29,6 +29,7 @@ pub struct DenoFlags {
pub allow_hrtime: bool,
pub no_prompts: bool,
pub no_fetch: bool,
pub seed: Option<u64>,
pub v8_flags: Option<Vec<String>>,
pub xeval_replvar: Option<String>,
pub xeval_delim: Option<String>,
@ -145,6 +146,19 @@ To get help on the another subcommands (run in this case):
.help("Load compiler configuration file")
.takes_value(true)
.global(true),
).arg(
Arg::with_name("seed")
.long("seed")
.value_name("NUMBER")
.help("Seed Math.random()")
.takes_value(true)
.validator(|val: String| {
match val.parse::<u64>() {
Ok(_) => Ok(()),
Err(_) => Err("Seed should be a number".to_string())
}
})
.global(true),
).arg(
Arg::with_name("v8-options")
.long("v8-options")
@ -379,6 +393,22 @@ pub fn parse_flags(matches: &ArgMatches) -> DenoFlags {
v8_flags.insert(0, "deno".to_string());
flags.v8_flags = Some(v8_flags);
}
if matches.is_present("seed") {
let seed_string = matches.value_of("seed").unwrap();
let seed = seed_string.parse::<u64>().unwrap();
flags.seed = Some(seed);
let v8_seed_flag = format!("--random-seed={}", seed);
match flags.v8_flags {
Some(ref mut v8_flags) => {
v8_flags.push(v8_seed_flag);
}
None => {
flags.v8_flags = Some(svec!["deno", v8_seed_flag]);
}
}
}
flags = parse_run_args(flags, matches);
// flags specific to "run" subcommand
@ -1112,4 +1142,42 @@ mod tests {
assert_eq!(subcommand, DenoSubcommand::Run);
assert_eq!(argv, svec!["deno", "script.ts"]);
}
#[test]
fn test_flags_from_vec_28() {
let (flags, subcommand, argv) =
flags_from_vec(svec!["deno", "--seed", "250", "run", "script.ts"]);
assert_eq!(
flags,
DenoFlags {
seed: Some(250 as u64),
v8_flags: Some(svec!["deno", "--random-seed=250"]),
..DenoFlags::default()
}
);
assert_eq!(subcommand, DenoSubcommand::Run);
assert_eq!(argv, svec!["deno", "script.ts"])
}
#[test]
fn test_flags_from_vec_29() {
let (flags, subcommand, argv) = flags_from_vec(svec![
"deno",
"--seed",
"250",
"--v8-flags=--expose-gc",
"run",
"script.ts"
]);
assert_eq!(
flags,
DenoFlags {
seed: Some(250 as u64),
v8_flags: Some(svec!["deno", "--expose-gc", "--random-seed=250"]),
..DenoFlags::default()
}
);
assert_eq!(subcommand, DenoSubcommand::Run);
assert_eq!(argv, svec!["deno", "script.ts"])
}
}

View file

@ -2211,10 +2211,17 @@ fn op_host_post_message(
}
fn op_get_random_values(
_state: &ThreadSafeState,
state: &ThreadSafeState,
_base: &msg::Base<'_>,
data: Option<PinnedBuf>,
) -> Box<OpWithError> {
thread_rng().fill(&mut data.unwrap()[..]);
if let Some(ref seeded_rng) = state.seeded_rng {
let mut rng = seeded_rng.lock().unwrap();
rng.fill(&mut data.unwrap()[..]);
} else {
let mut rng = thread_rng();
rng.fill(&mut data.unwrap()[..]);
}
Box::new(ok_future(empty_buf()))
}

View file

@ -23,6 +23,8 @@ use deno::PinnedBuf;
use futures::future::Either;
use futures::future::Shared;
use futures::Future;
use rand::rngs::StdRng;
use rand::SeedableRng;
use std;
use std::collections::HashMap;
use std::collections::HashSet;
@ -82,6 +84,7 @@ pub struct State {
pub dispatch_selector: ops::OpSelector,
/// Reference to global progress bar.
pub progress: Progress,
pub seeded_rng: Option<Mutex<StdRng>>,
/// Set of all URLs that have been compiled. This is a hacky way to work
/// around the fact that --reload will force multiple compilations of the same
@ -295,6 +298,11 @@ impl ThreadSafeState {
}
}
let mut seeded_rng = None;
if let Some(seed) = flags.seed {
seeded_rng = Some(Mutex::new(StdRng::seed_from_u64(seed)));
};
ThreadSafeState(Arc::new(State {
main_module,
dir,
@ -312,6 +320,7 @@ impl ThreadSafeState {
resource,
dispatch_selector,
progress,
seeded_rng,
compiled: Mutex::new(HashSet::new()),
}))
}

11
tests/seed_random.js Normal file
View file

@ -0,0 +1,11 @@
for (let i = 0; i < 10; ++i) {
console.log(Math.random());
}
const arr = new Uint8Array(32);
crypto.getRandomValues(arr);
console.log(arr);
crypto.getRandomValues(arr);
console.log(arr);

12
tests/seed_random.js.out Normal file
View file

@ -0,0 +1,12 @@
0.858562739044346
0.8973397944553141
0.15335012655691727
0.36867387434349963
0.3591039342838782
0.7044499748617652
0.7461423057751548
0.3824611207183364
0.5950178237266042
0.22440633214343908
Uint8Array [ 31, 147, 233, 143, 64, 159, 189, 114, 137, 153, 196, 156, 133, 210, 78, 4, 125, 255, 147, 234, 169, 149, 228, 46, 166, 246, 137, 49, 50, 182, 106, 219 ]
Uint8Array [ 220, 209, 104, 94, 239, 165, 8, 254, 123, 163, 160, 177, 229, 105, 171, 232, 236, 71, 107, 28, 132, 143, 113, 44, 86, 251, 159, 102, 20, 119, 174, 230 ]

2
tests/seed_random.test Normal file
View file

@ -0,0 +1,2 @@
args: run --seed=100 tests/seed_random.js
output: tests/seed_random.js.out

View file

@ -635,6 +635,7 @@ OPTIONS:
--allow-write=<allow-write> Allow file system write access
-c, --config <FILE> Load compiler configuration file
--importmap <FILE> Load import map file
--seed <NUMBER> Seed Math.random() and crypto.getRandomValues()
--v8-flags=<v8-flags> Set V8 command line options
SUBCOMMANDS: