#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::vec;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
use core::fmt::Debug;
pub trait Load {
type Error;
fn load(&mut self, destination: &mut [u8]) -> Result<(), Self::Error>;
}
#[cfg(feature = "std")]
impl<T> Load for T
where
T: std::io::Read,
{
type Error = std::io::Error;
fn load(&mut self, destination: &mut [u8]) -> Result<(), Self::Error> {
self.read_exact(destination)
}
}
#[derive(Clone, Debug)]
pub struct BufferedLoader<Buffer, Loader>
where
Buffer: AsRef<[u8]> + AsMut<[u8]> + Debug,
Loader: Load,
{
loader: Loader,
buffer: Buffer,
offset: usize,
}
impl<const N: usize, Loader> BufferedLoader<[u8; N], Loader>
where
Loader: Load,
{
pub fn new_static(loader: Loader) -> Self {
Self::new([0u8; N], loader)
}
}
#[cfg(feature = "alloc")]
impl<Loader> BufferedLoader<Vec<u8>, Loader>
where
Loader: Load,
{
pub fn new_dynamic(loader: Loader, buffer_size: usize) -> Self {
Self::new(vec![0u8; buffer_size], loader)
}
pub fn resize(&mut self, new_size: usize) {
self.buffer.resize(new_size, 0);
self.offset = new_size;
}
}
#[cfg(feature = "alloc")]
impl<Loader> BufferedLoader<Box<[u8]>, Loader>
where
Loader: Load,
{
pub fn new_heap(loader: Loader, buffer_size: usize) -> Self {
Self::new(vec![0u8; buffer_size].into_boxed_slice(), loader)
}
}
impl<Buffer, Loader> BufferedLoader<Buffer, Loader>
where
Buffer: AsRef<[u8]> + AsMut<[u8]> + Debug,
Loader: Load,
{
pub fn new(buffer: Buffer, loader: Loader) -> Self {
let offset = buffer.as_ref().len();
Self {
loader,
buffer,
offset,
}
}
pub fn loader(&mut self) -> &mut Loader {
self.offset = self.buffer.as_ref().len();
&mut self.loader
}
}
impl<Buffer, Loader> Load for BufferedLoader<Buffer, Loader>
where
Buffer: AsRef<[u8]> + AsMut<[u8]> + Debug,
Loader: Load,
{
type Error = Loader::Error;
fn load(&mut self, mut destination: &mut [u8]) -> Result<(), Self::Error> {
if destination.is_empty() {
return Ok(());
}
let buffer = self.buffer.as_mut();
let buffer_size = buffer.len();
let buffer_remaining = buffer_size - self.offset;
if destination.len() <= buffer_remaining {
let end = self.offset + destination.len();
destination.copy_from_slice(&buffer[self.offset..end]);
self.offset = end;
} else {
if buffer_remaining > 0 {
destination[..buffer_remaining].copy_from_slice(&buffer[self.offset..buffer_size]);
let copied = buffer_size - self.offset;
destination = &mut destination[copied..];
}
let buffers = destination.len() / buffer_size;
let remainder = destination.len() % buffer_size;
if buffers > 0 {
let buffers_bytes = buffers * buffer_size;
self.loader.load(&mut destination[..buffers_bytes])?;
destination = &mut destination[buffers_bytes..];
}
if remainder > 0 {
self.loader.load(buffer)?;
destination.copy_from_slice(&buffer[..remainder]);
self.offset = remainder;
} else {
self.offset = buffer_size;
}
}
Ok(())
}
}
#[cfg(test)]
pub mod test {
use core::convert::Infallible;
use super::*;
#[derive(Default)]
struct Increment(u8);
impl Load for Increment {
type Error = Infallible;
fn load(&mut self, destination: &mut [u8]) -> Result<(), Self::Error> {
for each in destination {
*each = self.0;
self.0 = self.0.wrapping_add(1);
}
Ok(())
}
}
#[test]
fn test_static_buffered_loader() {
let mut loader: BufferedLoader<[u8; 8], _> =
BufferedLoader::new_static(Increment::default());
let mut buf = [0u8; 4];
loader.load(&mut buf).unwrap();
assert_eq!(buf, [0, 1, 2, 3]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [4, 5, 6, 7]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [8, 9, 10, 11]);
let mut buf = [0u8; 12];
loader.load(&mut buf).unwrap();
assert_eq!(buf, [12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]);
let mut buf = [0u8; 3];
loader.load(&mut buf).unwrap();
assert_eq!(buf, [24, 25, 26]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [27, 28, 29]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [30, 31, 32]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [33, 34, 35]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [36, 37, 38]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [39, 40, 41]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [42, 43, 44]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [45, 46, 47]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [48, 49, 50]);
}
#[test]
fn test_dynamic_buffered_loader() {
let mut loader = BufferedLoader::new_dynamic(Increment::default(), 8);
let mut buf = [0u8; 4];
loader.load(&mut buf).unwrap();
assert_eq!(buf, [0, 1, 2, 3]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [4, 5, 6, 7]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [8, 9, 10, 11]);
let mut buf = [0u8; 12];
loader.load(&mut buf).unwrap();
assert_eq!(buf, [12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]);
let mut buf = [0u8; 3];
loader.load(&mut buf).unwrap();
assert_eq!(buf, [24, 25, 26]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [27, 28, 29]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [30, 31, 32]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [33, 34, 35]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [36, 37, 38]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [39, 40, 41]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [42, 43, 44]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [45, 46, 47]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [48, 49, 50]);
}
#[test]
fn test_boxed_slice_buffered_loader() {
let mut loader = BufferedLoader::new_heap(Increment::default(), 8);
let mut buf = [0u8; 4];
loader.load(&mut buf).unwrap();
assert_eq!(buf, [0, 1, 2, 3]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [4, 5, 6, 7]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [8, 9, 10, 11]);
let mut buf = [0u8; 12];
loader.load(&mut buf).unwrap();
assert_eq!(buf, [12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]);
let mut buf = [0u8; 3];
loader.load(&mut buf).unwrap();
assert_eq!(buf, [24, 25, 26]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [27, 28, 29]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [30, 31, 32]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [33, 34, 35]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [36, 37, 38]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [39, 40, 41]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [42, 43, 44]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [45, 46, 47]);
loader.load(&mut buf).unwrap();
assert_eq!(buf, [48, 49, 50]);
}
}