artichoke_backend/extn/core/random/
trampoline.rs

1//! Glue between mruby FFI and `ENV` Rust implementation.
2
3use spinoso_string::String;
4
5use super::{Random, Rng, Seed};
6use crate::convert::implicitly_convert_to_int;
7use crate::extn::prelude::*;
8
9pub fn initialize(interp: &mut Artichoke, seed: Option<Value>, into: Value) -> Result<Value, Error> {
10    let seed: Seed = interp.try_convert_mut(seed)?;
11    let random = if let Some(seed) = seed.to_mt_seed() {
12        Random::with_array_seed(seed)
13    } else {
14        Random::new()?
15    };
16    let random = Rng::Instance(Box::new(random));
17    let random = Rng::box_into_value(random, into, interp)?;
18    Ok(random)
19}
20
21pub fn equal(interp: &mut Artichoke, mut rand: Value, mut other: Value) -> Result<Value, Error> {
22    let random = unsafe { Rng::unbox_from_value(&mut rand, interp)? };
23    let other = unsafe { Rng::unbox_from_value(&mut other, interp)? };
24    let eql = *random == *other;
25    Ok(interp.convert(eql))
26}
27
28pub fn bytes(interp: &mut Artichoke, mut rand: Value, size: Value) -> Result<Value, Error> {
29    let mut random = unsafe { Rng::unbox_from_value(&mut rand, interp)? };
30    let size = implicitly_convert_to_int(interp, size)?;
31    let mut buf = match usize::try_from(size) {
32        Ok(0) => {
33            let s = String::binary(vec![]);
34            return String::alloc_value(s, interp);
35        }
36        Ok(len) => vec![0; len],
37        Err(_) => return Err(ArgumentError::with_message("negative string size (or size too big)").into()),
38    };
39    match &mut *random {
40        Rng::Global => interp.prng_mut()?.fill_bytes(&mut buf),
41        Rng::Instance(random) => random.fill_bytes(&mut buf),
42    }
43    let s = String::binary(buf);
44    String::alloc_value(s, interp)
45}
46
47pub fn rand(interp: &mut Artichoke, mut rand: Value, max: Option<Value>) -> Result<Value, Error> {
48    let mut random = unsafe { Rng::unbox_from_value(&mut rand, interp)? };
49    let max = interp.try_convert_mut(max)?;
50    let num = match &mut *random {
51        Rng::Global => spinoso_random::rand(interp.prng_mut()?, max)?,
52        Rng::Instance(random) => spinoso_random::rand(random, max)?,
53    };
54    Ok(interp.convert_mut(num))
55}
56
57pub fn seed(interp: &mut Artichoke, mut rand: Value) -> Result<Value, Error> {
58    let random = unsafe { Rng::unbox_from_value(&mut rand, interp)? };
59    let seed = match &*random {
60        Rng::Global => interp.prng()?.seed(),
61        Rng::Instance(random) => random.seed(),
62    };
63    let seed = seed
64        .try_into()
65        .map_err(|_| Fatal::with_message("Got random seed larger than i128"))?;
66    interp.try_convert(Seed::from_mt_seed_lossy(seed))
67}
68
69pub fn new_seed(interp: &mut Artichoke) -> Result<Value, Error> {
70    let seed = spinoso_random::new_seed()?;
71    let seed = Seed::from_mt_seed_lossy(seed);
72    interp.try_convert(seed)
73}
74
75pub fn srand(interp: &mut Artichoke, seed: Option<Value>) -> Result<Value, Error> {
76    let seed: Seed = interp.try_convert_mut(seed)?;
77    let old_seed = interp
78        .prng()?
79        .seed()
80        .try_into()
81        .map_err(|_| Fatal::with_message("Got random seed larger than i128"))?;
82    let old_seed = Seed::from_mt_seed_lossy(old_seed);
83
84    let new_random = if let Some(seed) = seed.to_mt_seed() {
85        Random::with_array_seed(seed)
86    } else {
87        Random::new()?
88    };
89    // "Reseed" by replacing the RNG with a newly seeded one.
90    let prng = interp.prng_mut()?;
91    *prng = new_random;
92
93    interp.try_convert(old_seed)
94}
95
96pub fn urandom(interp: &mut Artichoke, size: Value) -> Result<Value, Error> {
97    let size = implicitly_convert_to_int(interp, size)?;
98    let mut buf = match usize::try_from(size) {
99        Ok(0) => {
100            let s = String::binary(vec![]);
101            return String::alloc_value(s, interp);
102        }
103        Ok(len) => vec![0; len],
104        Err(_) => return Err(ArgumentError::with_message("negative string size (or size too big)").into()),
105    };
106    spinoso_random::urandom(&mut buf)?;
107    let s = String::binary(buf);
108    String::alloc_value(s, interp)
109}