use std::collections::TryReserveError;
use std::io::Error;
use std::io::ErrorKind;
use std::io::Result;
use std::io::SeekFrom;
use crate::Buffer;
use crate::Input;
use crate::Seekable;
use crate::SeekableInput;
use crate::buffered::DEFAULT_BUFFER_CAPACITY;
use crate::buffered::EnsuredBufferedInput;
use crate::util::SliceRange;
#[path = "internal.rs"]
mod internal;
use internal::ensure_available_impl;
use internal::fill_more_impl;
use internal::fill_until_impl;
use internal::read_fully_unchecked_impl;
use internal::read_unchecked_impl;
#[must_use]
#[derive(Debug)]
pub struct BufferedInput<I>
where
I: Input,
I::Item: Clone + Default,
{
inner: I,
buffer: Buffer<I::Item>,
}
impl<I> BufferedInput<I>
where
I: Input,
I::Item: Clone + Default,
{
#[inline(always)]
pub fn new(inner: I) -> Self {
Self::with_capacity(inner, DEFAULT_BUFFER_CAPACITY)
}
#[inline]
pub fn with_capacity(inner: I, capacity: usize) -> Self {
Self {
inner,
buffer: Buffer::with_capacity(capacity),
}
}
#[inline]
pub fn try_with_capacity(inner: I, capacity: usize) -> std::result::Result<Self, TryReserveError> {
Ok(Self {
inner,
buffer: Buffer::try_with_capacity(capacity)?,
})
}
#[inline]
pub fn ensure(input: I) -> EnsuredBufferedInput<I> {
if input.is_buffered() {
EnsuredBufferedInput::AlreadyBuffered(input)
} else {
EnsuredBufferedInput::Buffered(Self::new(input))
}
}
#[inline]
#[must_use = "the boxed input must be retained or used"]
pub fn ensure_boxed<'a>(input: I) -> Box<dyn Input<Item = I::Item> + 'a>
where
I: 'a,
I::Item: 'a,
{
if input.is_buffered() {
Box::new(input)
} else {
Box::new(Self::new(input))
}
}
#[inline(always)]
#[must_use]
pub const fn inner(&self) -> &I {
&self.inner
}
#[inline(always)]
#[must_use]
pub fn inner_mut(&mut self) -> &mut I {
&mut self.inner
}
#[inline(always)]
#[must_use = "the returned inner input and unread buffer must be handled"]
pub fn into_parts(self) -> (I, Buffer<I::Item>) {
(self.inner, self.buffer)
}
#[inline(always)]
#[must_use]
pub fn capacity(&self) -> usize {
self.buffer.capacity()
}
#[inline(always)]
#[must_use]
pub fn unread_len(&self) -> usize {
self.buffer.available()
}
#[inline(always)]
#[must_use]
pub fn unread(&self) -> &[I::Item] {
self.buffer.readable()
}
#[inline(always)]
pub fn try_reserve_capacity(
&mut self,
capacity: usize,
) -> std::result::Result<(), std::collections::TryReserveError> {
self.buffer.try_reserve_capacity(capacity)
}
#[inline(always)]
pub unsafe fn consume(&mut self, count: usize) {
unsafe {
self.buffer.consume(count);
}
}
#[inline]
pub unsafe fn copy_unread_to(&self, output: &mut [I::Item], output_index: usize, count: usize) {
debug_assert!(
SliceRange::range_fits(output.len(), output_index, count),
"unchecked unread destination range exceeds output buffer"
);
debug_assert!(
count <= self.buffer.available(),
"unchecked unread copy exceeds available buffer items"
);
unsafe {
let source = self.buffer.readable().get_unchecked(..count);
let output = output.get_unchecked_mut(output_index..output_index + count);
output.clone_from_slice(source);
}
}
#[inline(always)]
pub fn fill_more(&mut self) -> Result<bool> {
fill_more_impl(&mut self.inner, &mut self.buffer)
}
#[inline(always)]
pub fn fill_until(&mut self, count: usize) -> Result<bool> {
fill_until_impl(&mut self.inner, &mut self.buffer, count)
}
#[inline(always)]
pub fn ensure_available(&mut self, count: usize) -> Result<()> {
ensure_available_impl(&mut self.inner, &mut self.buffer, count)
}
#[inline(always)]
pub unsafe fn read_unchecked(
&mut self,
output: &mut [I::Item],
output_index: usize,
count: usize,
) -> Result<usize> {
unsafe { read_unchecked_impl(&mut self.inner, &mut self.buffer, output, output_index, count) }
}
#[inline(always)]
pub fn read(&mut self, output: &mut [I::Item]) -> Result<usize> {
unsafe { self.read_unchecked(output, 0, output.len()) }
}
#[inline(always)]
pub unsafe fn read_fully_unchecked(
&mut self,
output: &mut [I::Item],
output_index: usize,
count: usize,
) -> Result<usize> {
unsafe { read_fully_unchecked_impl(&mut self.inner, &mut self.buffer, output, output_index, count) }
}
#[inline(always)]
pub fn read_fully(&mut self, output: &mut [I::Item]) -> Result<usize> {
unsafe { self.read_fully_unchecked(output, 0, output.len()) }
}
pub fn seek_to(&mut self, position: SeekFrom) -> Result<u64>
where
I: SeekableInput,
{
match position {
SeekFrom::Current(offset) => {
let previous_cursor = self.buffer.position();
if self.seek_within_buffer(offset) {
let result = self.stream_position();
if result.is_err() {
let current_cursor = self.buffer.position();
unsafe {
if current_cursor > previous_cursor {
self.buffer.rewind(current_cursor - previous_cursor);
} else {
self.buffer.consume(previous_cursor - current_cursor);
}
}
}
return result;
}
let position = self.seek_relative_slow(offset)?;
self.discard_buffer();
Ok(position)
}
other => {
let position = Seekable::seek_to(&mut self.inner, other)?;
self.discard_buffer();
Ok(position)
}
}
}
#[inline]
pub fn stream_position(&mut self) -> Result<u64>
where
I: SeekableInput,
{
let position = Seekable::seek_to(&mut self.inner, SeekFrom::Current(0))?;
let unread = self.unread_len() as u64;
position.checked_sub(unread).ok_or_else(|| {
Error::new(
ErrorKind::InvalidData,
"buffered unread items exceed wrapped input position",
)
})
}
#[inline]
fn seek_relative_slow(&mut self, offset: i64) -> Result<u64>
where
I: SeekableInput,
{
let unread = i64::try_from(self.unread_len())
.map_err(|_| Error::new(ErrorKind::InvalidInput, "buffered unread item count exceeds i64"))?;
let adjusted = offset.checked_sub(unread).ok_or_else(|| {
Error::new(
ErrorKind::InvalidInput,
"current seek offset underflows after buffered adjustment",
)
})?;
Seekable::seek_to(&mut self.inner, SeekFrom::Current(adjusted))
}
#[must_use]
fn seek_within_buffer(&mut self, offset: i64) -> bool {
if offset >= 0 {
let count = offset as u64;
if count <= self.unread_len() as u64 {
let count = count as usize;
unsafe {
self.buffer.consume(count);
}
return true;
}
return false;
}
let count = offset.unsigned_abs();
if count <= self.buffer.position() as u64 {
let count = count as usize;
unsafe {
self.buffer.rewind(count);
}
return true;
}
false
}
#[inline(always)]
fn discard_buffer(&mut self) {
self.buffer.clear();
}
}
impl<I> Input for BufferedInput<I>
where
I: Input,
I::Item: Clone + Default,
{
type Item = I::Item;
#[inline(always)]
fn is_buffered(&self) -> bool {
true
}
#[inline(always)]
unsafe fn read_unchecked(&mut self, output: &mut [I::Item], output_index: usize, count: usize) -> Result<usize> {
unsafe { BufferedInput::read_unchecked(self, output, output_index, count) }
}
#[inline(always)]
fn read(&mut self, output: &mut [I::Item]) -> Result<usize> {
BufferedInput::read(self, output)
}
#[inline(always)]
unsafe fn read_fully_unchecked(&mut self, output: &mut [Self::Item], index: usize, count: usize) -> Result<usize> {
unsafe { BufferedInput::read_fully_unchecked(self, output, index, count) }
}
#[inline(always)]
fn read_fully(&mut self, output: &mut [Self::Item]) -> Result<usize> {
BufferedInput::read_fully(self, output)
}
}
impl<I> Seekable for BufferedInput<I>
where
I: SeekableInput,
<I as Input>::Item: Clone + Default,
{
type Unit = <I as Input>::Item;
#[inline(always)]
fn seek_to(&mut self, position: SeekFrom) -> Result<u64> {
BufferedInput::seek_to(self, position)
}
}