use crate::Scalar;
use std::{io::Read, ops::Range};
#[derive(Debug)]
pub(crate) struct BufferWindow {
pub(crate) buf: Box<[u8]>,
start_buf: *const u8,
pub(crate) start: *const u8,
pub(crate) end: *const u8,
pub prior_reads: usize,
}
pub enum BufferError {
Io(std::io::Error),
BufferFull,
}
impl BufferWindow {
#[inline]
pub fn from_slice(data: &[u8]) -> Self {
Self {
buf: Box::new([]),
start_buf: data.as_ptr(),
start: data.as_ptr(),
end: data.as_ptr_range().end,
prior_reads: 0,
}
}
#[inline]
pub fn advance_to(&mut self, ptr: *const u8) {
debug_assert!((self.start..=self.end).contains(&ptr));
self.start = ptr;
}
#[inline]
pub fn advance(&mut self, amt: usize) {
let ptr = unsafe { self.start.add(amt) };
debug_assert!((self.start..=self.end).contains(&ptr));
self.start = ptr;
}
#[inline]
pub fn window(&self) -> &[u8] {
unsafe { std::slice::from_raw_parts(self.start, self.window_len()) }
}
#[inline]
pub fn window_len(&self) -> usize {
unsafe { self.end.offset_from(self.start) as usize }
}
#[inline]
pub fn position(&self) -> usize {
self.prior_reads + self.consumed_data()
}
#[inline]
pub fn consumed_data(&self) -> usize {
unsafe { self.start.offset_from(self.start_buf) as usize }
}
#[inline]
pub fn get(&self, range: Range<*const u8>) -> Scalar<'_> {
debug_assert!(range.start >= self.start_buf);
debug_assert!(range.end <= self.end);
let len = unsafe { range.end.offset_from(range.start) as usize };
let sl = unsafe { std::slice::from_raw_parts(range.start, len) };
Scalar::new(sl)
}
#[inline]
pub fn fill_buf(&mut self, mut reader: impl Read) -> Result<usize, BufferError> {
let carry_over = self.window_len();
if carry_over >= self.buf.len() {
return Ok(0);
}
if carry_over != 0 {
if carry_over >= self.buf.len() {
return Err(BufferError::BufferFull);
}
self.buf.copy_within(self.consumed_data().., 0);
}
self.prior_reads += self.consumed_data();
self.start = self.buf.as_ptr();
self.end = unsafe { self.buf.as_ptr().add(carry_over) };
match reader.read(&mut self.buf[carry_over..]) {
Ok(r) => {
self.start = self.buf.as_ptr();
self.end = unsafe { self.end.add(r) };
Ok(r)
}
Err(e) => Err(BufferError::Io(e)),
}
}
#[inline]
pub fn split(&mut self, amt: usize) -> &[u8] {
let amt = amt.min(self.window_len());
let window = unsafe { std::slice::from_raw_parts(self.start, amt) };
self.start = unsafe { self.start.add(amt) };
window
}
}
#[derive(Debug)]
pub struct BufferWindowBuilder {
buffer: Option<Box<[u8]>>,
buffer_len: usize,
}
impl Default for BufferWindowBuilder {
fn default() -> Self {
let buffer_len = 32 * 1024;
Self {
buffer: None,
buffer_len,
}
}
}
impl BufferWindowBuilder {
#[inline]
pub fn buffer(mut self, val: Box<[u8]>) -> BufferWindowBuilder {
self.buffer = Some(val);
self
}
#[inline]
pub fn buffer_len(mut self, val: usize) -> BufferWindowBuilder {
self.buffer_len = val;
self
}
#[inline]
pub fn build(self) -> BufferWindow {
let init_len = self.buffer_len;
let buf = self
.buffer
.unwrap_or_else(|| vec![0; init_len].into_boxed_slice());
let start = buf.as_ptr_range().start;
let end = buf.as_ptr_range().start;
let start_buf = start;
BufferWindow {
buf,
start,
start_buf,
end,
prior_reads: 0,
}
}
}