use std::ffi::c_void;
mod ffi {
use std::ffi::c_void;
unsafe extern "C" {
pub fn arc4random_buf(buf: *mut c_void, nbytes: usize);
#[allow(dead_code)]
pub fn arc4random() -> u32;
pub fn arc4random_uniform(upper_bound: u32) -> u32;
}
}
pub fn fill_bytes(buffer: &mut [u8]) {
let buf_ptr = buffer.as_mut_ptr() as *mut c_void;
let buf_len = buffer.len();
unsafe {
ffi::arc4random_buf(buf_ptr, buf_len);
}
}
pub fn random_bytes(length: usize) -> Vec<u8> {
let mut buffer = vec![0u8; length];
fill_bytes(&mut buffer);
buffer
}
pub fn random_string(charset: &str, length: usize) -> String {
if charset.is_empty() {
return String::new();
}
let charset_bytes = charset.as_bytes();
let charset_len = charset_bytes.len() as u32;
let mut result = String::with_capacity(length);
for _ in 0..length {
let index = unsafe { ffi::arc4random_uniform(charset_len) } as usize;
result.push(charset_bytes[index] as char);
}
result
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fill_bytes() {
let mut buffer = [0u8; 16];
assert!(buffer.iter().all(|&b| b == 0));
fill_bytes(&mut buffer);
assert!(!buffer.iter().all(|&b| b == 0));
}
#[test]
fn test_random_bytes() {
let length = 32;
let random_data = random_bytes(length);
assert_eq!(random_data.len(), length);
let random_data2 = random_bytes(length);
assert_ne!(random_data, random_data2);
}
#[test]
fn test_random_string() {
let charset = "abcdefghijklmnopqrstuvwxyz";
let length = 20;
let random_str = random_string(charset, length);
assert_eq!(random_str.len(), length);
assert!(random_str.chars().all(|c| charset.contains(c)));
let random_str2 = random_string(charset, length);
assert_ne!(random_str, random_str2);
}
#[test]
fn test_random_string_empty_charset() {
let empty_charset = "";
let random_str = random_string(empty_charset, 10);
assert_eq!(random_str, "");
}
#[test]
fn test_random_string_zero_length() {
let charset = "abcdefghijklmnopqrstuvwxyz";
let random_str = random_string(charset, 0);
assert_eq!(random_str, "");
}
}