const BUFFER_SIZE: usize = 65536;
pub struct BufferedRandom {
buffer: [u8; BUFFER_SIZE],
position: usize,
available: usize,
}
impl BufferedRandom {
pub fn new() -> Self {
Self {
buffer: [0u8; BUFFER_SIZE],
position: 0,
available: 0,
}
}
#[inline]
pub fn fill(&mut self, dest: &mut [u8]) -> Result<(), getrandom::Error> {
let requested = dest.len();
if requested >= BUFFER_SIZE {
return getrandom::fill(dest);
}
let mut offset = 0;
while offset < requested {
if self.position >= self.available {
self.refill_buffer()?;
}
let remaining_in_buffer = self.available - self.position;
let remaining_to_copy = requested - offset;
let to_copy = remaining_in_buffer.min(remaining_to_copy);
dest[offset..offset + to_copy]
.copy_from_slice(&self.buffer[self.position..self.position + to_copy]);
self.position += to_copy;
offset += to_copy;
}
Ok(())
}
#[inline]
fn refill_buffer(&mut self) -> Result<(), getrandom::Error> {
getrandom::fill(&mut self.buffer)?;
self.position = 0;
self.available = BUFFER_SIZE;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_small_fill() {
let mut rng = BufferedRandom::new();
let mut data = [0u8; 16];
assert!(rng.fill(&mut data).is_ok());
assert!(data.iter().any(|&b| b != 0));
}
#[test]
fn test_large_fill() {
let mut rng = BufferedRandom::new();
let mut data = vec![0u8; 16384];
assert!(rng.fill(&mut data).is_ok());
assert!(data.iter().any(|&b| b != 0));
}
#[test]
fn test_multiple_fills() {
let mut rng = BufferedRandom::new();
for _ in 0..100 {
let mut data = [0u8; 64];
assert!(rng.fill(&mut data).is_ok());
}
}
#[test]
fn test_exact_buffer_size() {
let mut rng = BufferedRandom::new();
let mut data = vec![0u8; BUFFER_SIZE];
assert!(rng.fill(&mut data).is_ok());
}
#[test]
fn test_larger_than_buffer() {
let mut rng = BufferedRandom::new();
let mut data = vec![0u8; BUFFER_SIZE + 1];
assert!(rng.fill(&mut data).is_ok());
}
}