#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use core::fmt::Debug;
pub trait Load {
type Error;
fn load(&mut self, buf: &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, buf: &mut [u8]) -> Result<(), Self::Error> {
self.read_exact(buf)
}
}
#[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 {
loader,
buffer: [0u8; N],
offset: N,
}
}
}
#[cfg(feature = "alloc")]
impl<Loader> BufferedLoader<Vec<u8>, Loader>
where
Loader: Load,
{
pub fn new_dynamic(loader: Loader, buffer_size: usize) -> Self {
let mut buffer = Vec::with_capacity(buffer_size);
buffer.resize(buffer_size, 0);
Self {
loader,
buffer,
offset: buffer_size,
}
}
pub fn resize(&mut self, new_size: usize) {
let invalid = new_size > self.buffer.len();
self.buffer.resize(new_size, 0);
if invalid {
self.offset = new_size;
}
}
}
impl<Buffer, Loader> BufferedLoader<Buffer, Loader>
where
Buffer: AsRef<[u8]> + AsMut<[u8]> + Debug,
Loader: Load,
{
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 buf: &mut [u8]) -> Result<(), Self::Error> {
if buf.is_empty() {
return Ok(());
}
let buffer = self.buffer.as_mut();
let buffer_size = buffer.len();
let buffer_remaining = buffer_size - self.offset;
if buf.len() <= buffer_remaining {
let end = self.offset + buf.len();
buf.copy_from_slice(&buffer[self.offset..end]);
self.offset = end;
} else {
if buffer_remaining > 0 {
buf[..buffer_remaining].copy_from_slice(&buffer[self.offset..buffer_size]);
let copied = buffer_size - self.offset;
buf = &mut buf[copied..];
}
let buffers = buf.len() / buffer_size;
let remainder = buf.len() % buffer_size;
if buffers > 0 {
let buffers_bytes = buffers * buffer_size;
self.loader.load(&mut buf[..buffers_bytes])?;
buf = &mut buf[buffers_bytes..];
}
if remainder > 0 {
self.loader.load(buffer)?;
buf.copy_from_slice(&buffer[..remainder]);
self.offset = remainder;
} else {
self.offset = buffer_size;
}
}
Ok(())
}
}