use crate::seqstring::global_string;
use crate::stack::{Stack, pop, push};
use crate::value::Value;
use rand::{RngCore, rng};
use uuid::Uuid;
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_random_bytes(stack: Stack) -> Stack {
assert!(!stack.is_null(), "random-bytes: stack is empty");
let (stack, value) = unsafe { pop(stack) };
match value {
Value::Int(n) => {
if n < 0 {
panic!("random-bytes: byte count must be non-negative, got {}", n);
}
if n > 1024 {
panic!("random-bytes: byte count too large (max 1024), got {}", n);
}
let mut bytes = vec![0u8; n as usize];
rng().fill_bytes(&mut bytes);
let hex_str = hex::encode(&bytes);
unsafe { push(stack, Value::String(global_string(hex_str))) }
}
_ => panic!("random-bytes: expected Int on stack, got {:?}", value),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_uuid4(stack: Stack) -> Stack {
assert!(!stack.is_null(), "uuid4: stack is empty");
let uuid = Uuid::new_v4();
unsafe { push(stack, Value::String(global_string(uuid.to_string()))) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn patch_seq_random_int(stack: Stack) -> Stack {
assert!(!stack.is_null(), "random-int: stack is empty");
let (stack, max_val) = unsafe { pop(stack) };
let (stack, min_val) = unsafe { pop(stack) };
match (min_val, max_val) {
(Value::Int(min), Value::Int(max)) => {
let result = if min >= max {
min } else {
random_int_range(min, max)
};
unsafe { push(stack, Value::Int(result)) }
}
(min, max) => panic!(
"random-int: expected (Int, Int) on stack, got ({:?}, {:?})",
min, max
),
}
}
fn random_int_range(min: i64, max: i64) -> i64 {
let range = (max as u64).wrapping_sub(min as u64);
if range == 0 {
return min;
}
let threshold = u64::MAX - (u64::MAX % range);
loop {
let mut bytes = [0u8; 8];
rng().fill_bytes(&mut bytes);
let val = u64::from_le_bytes(bytes);
if val < threshold {
let result = (min as u64).wrapping_add(val % range);
return result as i64;
}
}
}