use std::time::{SystemTime, UNIX_EPOCH};
use crate::error::VBResult;
use crate::state::random;
use crate::value::VBVariant;
fn timer_bits() -> u32 {
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default();
let seconds = (now.as_secs() % 86_400) as f32 + now.subsec_millis() as f32 / 1000.0;
seconds.to_bits()
}
pub fn randomize(value: Option<VBVariant>) -> VBResult<()> {
let bits = match value {
None | Some(VBVariant::Empty) => timer_bits(),
Some(v) => {
let number = v.as_f64()?;
(number.to_bits() >> 32) as u32
}
};
random::randomize(bits);
Ok(())
}
#[cfg(test)]
mod tests {
use super::randomize;
use crate::error::err_number;
use crate::library::math::rnd::rnd;
use crate::state::random::{seed, set_seed, MODULUS};
use crate::state::test_support::TEST_LOCK;
use crate::value::VBSingle;
use crate::value::VBVariant;
fn expected(seed: u32) -> f32 {
seed as f32 / MODULUS as f32
}
fn as_single(value: VBVariant) -> f32 {
match value {
VBVariant::Single(v) => v,
other => panic!("expected Single, got {other:?}"),
}
}
#[test]
fn randomize_with_value_is_deterministic() {
let _guard = TEST_LOCK.lock().unwrap();
set_seed(0);
randomize(Some(VBVariant::from_double(42.0))).unwrap();
assert_eq!(seed(), 0x0040_4500);
let next = as_single(rnd(None).unwrap());
assert_eq!(next, f32::from_bits(0x3EAD_9F86));
}
#[test]
fn randomize_preserves_the_low_byte_of_the_seed() {
let _guard = TEST_LOCK.lock().unwrap();
set_seed(0x0000_0123);
randomize(Some(VBVariant::from_double(1.0))).unwrap();
assert_eq!(seed(), 0x003F_F023);
}
#[test]
fn randomize_with_negative_value_can_set_a_full_32_bit_seed() {
let _guard = TEST_LOCK.lock().unwrap();
set_seed(0);
randomize(Some(VBVariant::from_double(-1.0))).unwrap();
assert_eq!(seed(), 0xFFBF_F000);
assert_eq!(
as_single(rnd(Some(&VBSingle::from(0.0))).unwrap()),
expected(0xFFBF_F000)
);
let next = as_single(rnd(None).unwrap());
assert_eq!(next, f32::from_bits(0x3E87_9D86));
assert!((0.0..1.0).contains(&next));
}
#[test]
fn omitted_argument_reseeds_from_the_timer() {
let _guard = TEST_LOCK.lock().unwrap();
set_seed(0x1234_5678);
randomize(None).unwrap();
let reseeded = seed();
assert_ne!(reseeded, 0x1234_5678);
assert_eq!(reseeded & 0xFF, 0x78);
let value = as_single(rnd(None).unwrap());
assert!((0.0..1.0).contains(&value));
}
#[test]
fn accepts_numeric_strings() {
let _guard = TEST_LOCK.lock().unwrap();
set_seed(0);
randomize(Some(VBVariant::from_string("42"))).unwrap();
assert_eq!(seed(), 0x0040_4500);
}
#[test]
fn rejects_non_numeric_values() {
let err = randomize(Some(VBVariant::from_string("not-a-number"))).unwrap_err();
assert_eq!(err.number, err_number::TYPE_MISMATCH);
}
#[test]
fn rejects_null() {
let err = randomize(Some(VBVariant::Null)).unwrap_err();
assert_eq!(err.number, err_number::INVALID_USE_OF_NULL);
}
}