diff --git a/Cargo.lock b/Cargo.lock index d7e2bfc88..29bc6b619 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3897,7 +3897,6 @@ dependencies = [ "parking_lot", "polling 3.11.0", "proptest", - "rand 0.9.2", "rustc-hash", "serde", "serde_json", diff --git a/crates/steel-core/Cargo.toml b/crates/steel-core/Cargo.toml index 31ec1eae0..9c58093b4 100644 --- a/crates/steel-core/Cargo.toml +++ b/crates/steel-core/Cargo.toml @@ -46,8 +46,7 @@ cargo-steel-lib = { path = "../cargo-steel-lib", version = "0.2.0", optional = t chrono = { version = "0.4.23", default-features = false, features = ["std", "clock"], optional = true } env_home = "0.1.0" weak-table = "0.3.2" -# TODO: Consider whether rand needs to be here -rand = "0.9.0" +getrandom = { version = "0.3.1", default-features = false } num-bigint = "0.4.6" num-rational = "0.4.2" num-traits = "0.2.19" @@ -110,7 +109,7 @@ steel-imbl = { version = "7.1", optional = true, features = ["serde"] } icu_casemap = "2.0.0" [target.'cfg(target_family = "wasm")'.dependencies] -getrandom = { version = "0.3.1", features = ["wasm_js"] } +getrandom = { version = "0.3.1", default-features = false, features = ["wasm_js"] } js-sys = "0.3.69" [target.'cfg(not(target_family = "wasm"))'.dependencies] @@ -126,7 +125,7 @@ criterion = "0.5.1" [features] # TODO: Deprecate the modules feature flag, it no longer does anything default = ["std", "modules"] -std = ["dep:chrono"] +std = ["getrandom/std", "dep:chrono"] modules = [] jit = ["dep:cranelift", "dep:cranelift-module", "dep:cranelift-jit"] sandbox = [] diff --git a/crates/steel-core/src/primitives/random.rs b/crates/steel-core/src/primitives/random.rs index 2089d91f1..a7a707172 100644 --- a/crates/steel-core/src/primitives/random.rs +++ b/crates/steel-core/src/primitives/random.rs @@ -1,9 +1,5 @@ -use rand::{prelude::*, rng}; - +use crate::steel_vm::builtin::BuiltInModule; use crate::steel_vm::register_fn::RegisterFn; -use crate::{rvals::Custom, steel_vm::builtin::BuiltInModule}; - -impl Custom for ThreadRng {} // pub(crate) const THREAD_RNG_DOC: DocTemplate<'static> = DocTemplate { // signature: "(thread-rng!) -> ThreadRng?", @@ -26,9 +22,35 @@ pub fn random_module() -> BuiltInModule { module // .register_fn("thread-rng!", thread_rng) // .register_doc("thread-rng!", THREAD_RNG_DOC) - .register_fn("rng->gen-usize", || rng().random::()) + .register_fn("rng->gen-usize", random_u64) // .register_doc("rng->gen-usize", RNG_GEN_USIZE) - .register_fn("rng->gen-range", |x: i64, y: i64| rng().random_range(x..y)); + .register_fn("rng->gen-range", random_range_i64); module } + +fn random_u64() -> u64 { + let mut bytes = [0u8; 8]; + getrandom::fill(&mut bytes).expect("getrandom failed"); + u64::from_ne_bytes(bytes) +} + +fn random_range_i64(start: i64, end: i64) -> i64 { + assert!(start < end, "random range is empty"); + let span = (end as i128 - start as i128) as u64; + if span == 1 { + return start; + } + let offset = random_range_u64(span) as i128; + (start as i128 + offset) as i64 +} + +fn random_range_u64(span: u64) -> u64 { + let zone = u64::MAX - (u64::MAX % span); + loop { + let value = random_u64(); + if value < zone { + return value % span; + } + } +} diff --git a/crates/steel-core/src/steel_vm/engine.rs b/crates/steel-core/src/steel_vm/engine.rs index 88e816561..d5efa9862 100644 --- a/crates/steel-core/src/steel_vm/engine.rs +++ b/crates/steel-core/src/steel_vm/engine.rs @@ -2743,7 +2743,7 @@ fn test_raw_engine() { fn test_ctx_func() { let mut engine = Engine::new(); - let mut module = BuiltInModule::new("test/module"); + let mut module = BuiltInModule::new("test/module-ctx-func"); module.register_fn("foo", |implicit: SteelVal| { println!("Called with implicit: {}", implicit); @@ -2755,7 +2755,9 @@ fn test_ctx_func() { engine.register_module(module); - engine.run("(require-builtin test/module)").unwrap(); + engine + .run("(require-builtin test/module-ctx-func)") + .unwrap(); engine.run("(foo)").unwrap(); engine.update_value("global-context", SteelVal::IntV(10)); engine.run("(foo)").unwrap(); @@ -2765,7 +2767,7 @@ fn test_ctx_func() { fn test_ctx_func_registration() { let mut engine = Engine::new(); - let mut module = BuiltInModule::new("test/module-func"); + let mut module = BuiltInModule::new("test/module-ctx-func-registration"); engine.register_value("global-context", SteelVal::StringV("Hello world!".into())); module.register_fn_with_ctx("global-context", "foo", |implicit: SteelVal| { @@ -2774,7 +2776,9 @@ fn test_ctx_func_registration() { engine.register_module(module); - engine.run("(require-builtin test/module-func)").unwrap(); + engine + .run("(require-builtin test/module-ctx-func-registration)") + .unwrap(); engine.run("(foo)").unwrap(); engine.update_value("global-context", SteelVal::IntV(10)); engine.run("(foo)").unwrap(); @@ -2784,7 +2788,7 @@ fn test_ctx_func_registration() { fn test_ctx_func_registration_multiple() { let mut engine = Engine::new(); - let mut module = BuiltInModule::new("test/module-ctx"); + let mut module = BuiltInModule::new("test/module-ctx-func-registration-multiple"); engine.register_value("global-context", SteelVal::StringV("Hello world!".into())); module.register_fn_with_ctx("global-context", "foo", |implicit: SteelVal| { @@ -2801,7 +2805,9 @@ fn test_ctx_func_registration_multiple() { engine.register_module(module); - engine.run("(require-builtin test/module-ctx)").unwrap(); + engine + .run("(require-builtin test/module-ctx-func-registration-multiple)") + .unwrap(); engine.run("(bar 10)").unwrap(); engine.update_value("global-context", SteelVal::IntV(10)); engine.run("(bar 100)").unwrap();