use super::{pair_bytes, sig, triple_bytes, u32_bytes, InputGenerator};
use crate::spec::types::OpSignature;
pub struct RandomUniform;
struct XorShift64 {
state: u64,
}
impl XorShift64 {
fn new(seed: u64) -> Self {
let state = if seed == 0 {
0x9E37_79B9_7F4A_7C15
} else {
seed
};
Self { state }
}
fn next_u32(&mut self) -> u32 {
let mut x = self.state;
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
self.state = x;
(x >> 32) as u32
}
}
impl InputGenerator for RandomUniform {
fn name(&self) -> &'static str {
"random_uniform"
}
fn handles(&self, signature: &OpSignature) -> bool {
sig::is_u32_any(signature) || sig::is_byte_input(signature)
}
fn generate(&self, signature: &OpSignature, seed: u64) -> Vec<(String, Vec<u8>)> {
let mut rng = XorShift64::new(seed);
if sig::is_unary_u32(signature) {
(0..1024)
.map(|idx| {
let value = rng.next_u32();
(format!("random:u32:{idx}"), u32_bytes(value))
})
.collect()
} else if sig::is_binary_u32(signature) {
(0..2048)
.map(|idx| {
let left = rng.next_u32();
let right = rng.next_u32();
(format!("random:pair:{idx}"), pair_bytes(left, right))
})
.collect()
} else if sig::is_ternary_u32(signature) {
(0..2048)
.map(|idx| {
let a = rng.next_u32();
let b = rng.next_u32();
let c = rng.next_u32();
(format!("random:triple:{idx}"), triple_bytes(a, b, c))
})
.collect()
} else if sig::is_byte_input(signature) {
random_buffers(&mut rng)
} else {
Vec::new()
}
}
}
fn random_buffers(rng: &mut XorShift64) -> Vec<(String, Vec<u8>)> {
let mut out = Vec::with_capacity(128);
for idx in 0..128 {
let len = (rng.next_u32() as usize) % 4097;
let mut bytes = Vec::with_capacity(len);
for _ in 0..len {
bytes.push((rng.next_u32() & 0xFF) as u8);
}
out.push((format!("random:bytes:{idx}:len{len}"), bytes));
}
out
}