shape_runtime/intrinsics/
random.rs1use crate::marshal::{register_typed_fn_0, register_typed_fn_1, register_typed_fn_2};
18use crate::module_exports::ModuleExports;
19use crate::typed_module_exports::{ConcreteReturn, ConcreteType, TypedReturn};
20use rand::{Rng, SeedableRng};
21use rand_chacha::ChaCha8Rng;
22use std::cell::RefCell;
23
24thread_local! {
25 static RNG: RefCell<ChaCha8Rng> = RefCell::new(ChaCha8Rng::from_entropy());
26}
27
28pub fn with_rng<F, R>(f: F) -> R
33where
34 F: FnOnce(&mut ChaCha8Rng) -> R,
35{
36 RNG.with(|rng| f(&mut *rng.borrow_mut()))
37}
38
39pub fn create_random_intrinsics_module() -> ModuleExports {
43 let mut module = ModuleExports::new("std::core::intrinsics::random");
44 module.description =
45 "Random number generation intrinsics (ChaCha8 thread-local PRNG)".to_string();
46
47 register_typed_fn_0::<_>(
48 &mut module,
49 "__intrinsic_random",
50 "Generate random f64 in [0, 1)",
51 ConcreteType::Number,
52 |_ctx| {
53 let value = with_rng(|rng| rng.r#gen::<f64>());
54 Ok(TypedReturn::Concrete(ConcreteReturn::F64(value)))
55 },
56 );
57
58 register_typed_fn_2::<_, f64, f64>(
59 &mut module,
60 "__intrinsic_random_int",
61 "Generate random integer in [lo, hi] (inclusive); returns as number",
62 [("lo", "number"), ("hi", "number")],
63 ConcreteType::Number,
64 |lo, hi, _ctx| {
65 let lo = lo as i64;
66 let hi = hi as i64;
67 if lo > hi {
68 return Err(format!(
69 "__intrinsic_random_int: lo ({}) must be <= hi ({})",
70 lo, hi
71 ));
72 }
73 let value = with_rng(|rng| rng.gen_range(lo..=hi));
74 Ok(TypedReturn::Concrete(ConcreteReturn::F64(value as f64)))
75 },
76 );
77
78 register_typed_fn_1::<_, f64>(
79 &mut module,
80 "__intrinsic_random_seed",
81 "Seed the thread-local RNG for reproducibility",
82 "seed",
83 "number",
84 ConcreteType::Unit,
85 |seed, _ctx| {
86 let seed = seed as u64;
87 with_rng(|rng| {
88 *rng = ChaCha8Rng::seed_from_u64(seed);
89 });
90 Ok(TypedReturn::Concrete(ConcreteReturn::Unit))
91 },
92 );
93
94 register_typed_fn_2::<_, f64, f64>(
95 &mut module,
96 "__intrinsic_random_normal",
97 "Generate random number from a normal distribution (Box-Muller)",
98 [("mean", "number"), ("std", "number")],
99 ConcreteType::Number,
100 |mean, std, _ctx| {
101 if std < 0.0 {
102 return Err("__intrinsic_random_normal: std must be non-negative".to_string());
103 }
104 let value = with_rng(|rng| {
105 let u1: f64 = rng.r#gen();
106 let u2: f64 = rng.r#gen();
107 let z = (-2.0 * u1.ln()).sqrt() * (2.0 * std::f64::consts::PI * u2).cos();
108 mean + std * z
109 });
110 Ok(TypedReturn::Concrete(ConcreteReturn::F64(value)))
111 },
112 );
113
114 register_typed_fn_1::<_, i64>(
115 &mut module,
116 "__intrinsic_random_array",
117 "Generate array of n random numbers in [0, 1)",
118 "n",
119 "int",
120 ConcreteType::ArrayNumber,
121 |n, _ctx| {
122 if n < 0 {
123 return Err("__intrinsic_random_array: n must be non-negative".to_string());
124 }
125 let n = n as usize;
126 let values: Vec<f64> = with_rng(|rng| (0..n).map(|_| rng.r#gen::<f64>()).collect());
127 Ok(TypedReturn::Concrete(ConcreteReturn::ArrayF64(values)))
128 },
129 );
130
131 module
132}