#[cfg(coverage)]
use std::cell::Cell;
use std::cmp::Ordering;
use std::convert::Infallible;
use std::io::Error;
use std::io::ErrorKind;
use std::io::Read;
use std::io::Result;
use std::io::Write;
use crate::Input;
use crate::Output;
use crate::capacity_const::DEFAULT_BUFFER_CAPACITY;
use crate::capacity_const::DEFAULT_COMPARE_BUFFER_SIZE;
use crate::capacity_const::DEFAULT_COPY_BUFFER_SIZE;
use crate::std_io::ext::ReadExt;
use crate::traits::validate_read_count;
use crate::util::allocation_error;
use crate::util::create_vec;
use crate::util::try_reserve_vec;
pub struct Streams {
_private: Infallible,
}
impl Streams {
#[inline(always)]
pub fn copy<R, W>(reader: &mut R, writer: &mut W) -> Result<u64>
where
R: Read + ?Sized,
W: Write + ?Sized,
{
std::io::copy(reader, writer)
}
#[inline(always)]
pub fn copy_at_most<R, W>(reader: &mut R, writer: &mut W, max_bytes: u64) -> Result<u64>
where
R: Read + ?Sized,
W: Write + ?Sized,
{
let mut reader = reader;
let mut writer = writer;
copy_at_most_impl(&mut reader, &mut writer, max_bytes, DEFAULT_COPY_BUFFER_SIZE)
}
#[inline(always)]
pub fn copy_at_most_with_buffer_size<R, W>(
reader: &mut R,
writer: &mut W,
max_bytes: u64,
buffer_size: usize,
) -> Result<u64>
where
R: Read + ?Sized,
W: Write + ?Sized,
{
let mut reader = reader;
let mut writer = writer;
copy_at_most_impl(&mut reader, &mut writer, max_bytes, buffer_size)
}
#[inline(always)]
pub fn copy_to_end_limited<R, W>(reader: &mut R, writer: &mut W, max_bytes: u64) -> Result<u64>
where
R: Read + ?Sized,
W: Write + ?Sized,
{
let mut reader = reader;
let mut writer = writer;
copy_to_end_limited_impl(&mut reader, &mut writer, max_bytes)
}
pub fn copy_input_to_output<T>(input: &mut dyn Input<Item = T>, output: &mut dyn Output<Item = T>) -> Result<u64>
where
T: Clone + Default,
{
let mut buffer = create_vec(DEFAULT_BUFFER_CAPACITY, T::default())?;
let mut copied = 0_u64;
loop {
let read = input.read_fully(&mut buffer)?;
validate_read_count(read, buffer.len())?;
if read == 0 {
return Ok(copied);
}
unsafe {
output.write_fully_unchecked(&buffer, 0, read)?;
}
copied = add_item_count(copied, read)?;
}
}
pub fn copy_input_to_output_at_most<T>(
input: &mut dyn Input<Item = T>,
output: &mut dyn Output<Item = T>,
max_items: u64,
) -> Result<u64>
where
T: Clone + Default,
{
if max_items == 0 {
return Ok(0);
}
let buffer_size = usize::try_from(max_items)
.unwrap_or(usize::MAX)
.min(DEFAULT_BUFFER_CAPACITY);
let mut buffer = create_vec(buffer_size, T::default())?;
let mut remaining = max_items;
let mut copied = 0_u64;
while remaining > 0 {
let requested = remaining.min(buffer.len() as u64) as usize;
let read = unsafe { input.read_fully_unchecked(&mut buffer, 0, requested)? };
validate_read_count(read, requested)?;
if read == 0 {
break;
}
unsafe {
output.write_fully_unchecked(&buffer, 0, read)?;
}
let read = read as u64;
remaining -= read;
copied = add_item_count(copied, read as usize)?;
}
Ok(copied)
}
pub fn copy_input_to_output_end_limited<T>(
input: &mut dyn Input<Item = T>,
output: &mut dyn Output<Item = T>,
max_items: u64,
) -> Result<u64>
where
T: Clone + Default,
{
let buffer_size = usize::try_from(max_items.saturating_add(1))
.unwrap_or(usize::MAX)
.min(DEFAULT_BUFFER_CAPACITY);
let mut buffer = create_vec(buffer_size, T::default())?;
let mut collected = Vec::new();
let mut remaining = max_items;
let mut copied = 0_u64;
loop {
let requested = remaining.saturating_add(1).min(buffer.len() as u64) as usize;
let read = unsafe { input.read_fully_unchecked(&mut buffer, 0, requested)? };
validate_read_count(read, requested)?;
if read == 0 {
let count = collected.len();
if count == 0 {
return Ok(copied);
}
unsafe {
output.write_fully_unchecked(&collected, 0, count)?;
}
return Ok(copied);
}
if (read as u64) > remaining {
return Err(Error::new(
ErrorKind::InvalidData,
format!("input exceeds maximum length of {max_items} items"),
));
}
try_reserve_vec(&mut collected, read).map_err(allocation_error)?;
collected.extend_from_slice(&buffer[..read]);
let read = read as u64;
remaining -= read;
copied = add_item_count(copied, read as usize)?;
}
}
#[inline(always)]
pub fn content_eq(left: &mut dyn Read, right: &mut dyn Read) -> Result<bool> {
Ok(Self::compare_content(left, right)? == Ordering::Equal)
}
#[inline(always)]
pub fn compare_content(left: &mut dyn Read, right: &mut dyn Read) -> Result<Ordering> {
Self::compare_content_with_buffer_size(left, right, DEFAULT_COMPARE_BUFFER_SIZE)
}
pub fn compare_content_with_buffer_size(
left: &mut dyn Read,
right: &mut dyn Read,
buffer_size: usize,
) -> Result<Ordering> {
if buffer_size == 0 {
return Err(Error::new(
ErrorKind::InvalidInput,
"compare buffer size must be greater than zero",
));
}
let mut left_buffer = create_vec(buffer_size, 0)?;
let mut right_buffer = create_vec(buffer_size, 0)?;
debug_assert_eq!(
left_buffer.len(),
right_buffer.len(),
"compare buffers must have identical lengths",
);
debug_assert!(!left_buffer.is_empty(), "compare buffers must not be empty",);
loop {
let left_count = left.read_exact_or_eof(&mut left_buffer)?;
let right_count = right.read_exact_or_eof(&mut right_buffer)?;
let n = left_count.min(right_count);
match left_buffer[..n].cmp(&right_buffer[..n]) {
Ordering::Equal => {}
ordering => return Ok(ordering),
}
match left_count.cmp(&right_count) {
Ordering::Equal if left_count == 0 => {
return Ok(Ordering::Equal);
}
Ordering::Equal => {}
ordering => return Ok(ordering),
}
}
}
}
fn copy_at_most_impl(reader: &mut dyn Read, writer: &mut dyn Write, max_bytes: u64, buffer_size: usize) -> Result<u64> {
if buffer_size == 0 {
return Err(Error::new(
ErrorKind::InvalidInput,
"copy buffer size must be greater than zero",
));
}
if max_bytes == 0 {
return Ok(0);
}
let buffer_size = usize::try_from(max_bytes).unwrap_or(usize::MAX).min(buffer_size);
let mut buffer = create_vec(buffer_size, 0)?;
let mut remaining = max_bytes;
let mut copied = 0;
while remaining > 0 {
let requested = remaining.min(buffer_size as u64) as usize;
match reader.read(&mut buffer[..requested]) {
Ok(0) => break,
Ok(count) => {
writer.write_all(&buffer[..count])?;
let count = count as u64;
remaining -= count;
copied += count;
}
Err(error) => {
if error.kind() == ErrorKind::Interrupted {
continue;
}
return Err(error);
}
}
}
Ok(copied)
}
fn copy_to_end_limited_impl(reader: &mut dyn Read, writer: &mut dyn Write, max_bytes: u64) -> Result<u64> {
let copied = copy_at_most_impl(reader, writer, max_bytes, DEFAULT_COPY_BUFFER_SIZE)?;
if copied < max_bytes {
return Ok(copied);
}
let mut byte = [0];
loop {
match reader.read(&mut byte) {
Ok(0) => return Ok(copied),
Ok(_) => {
return Err(Error::new(
ErrorKind::InvalidData,
format!("input exceeds maximum length of {max_bytes} bytes"),
));
}
Err(error) => {
if error.kind() == ErrorKind::Interrupted {
continue;
}
return Err(error);
}
}
}
}
#[cfg(coverage)]
thread_local! {
static COVERAGE_FAIL_NEXT_ADD_ITEM_COUNT: Cell<bool> = const { Cell::new(false) };
}
#[cfg(coverage)]
#[doc(hidden)]
#[inline(always)]
pub fn coverage_fail_next_add_item_count() {
COVERAGE_FAIL_NEXT_ADD_ITEM_COUNT.with(|state| state.set(true));
}
#[cfg(coverage)]
#[doc(hidden)]
#[inline(always)]
pub fn coverage_reset_add_item_count_hooks() {
COVERAGE_FAIL_NEXT_ADD_ITEM_COUNT.with(|state| state.set(false));
}
#[inline]
fn add_item_count(copied: u64, count: usize) -> Result<u64> {
#[cfg(coverage)]
if COVERAGE_FAIL_NEXT_ADD_ITEM_COUNT.with(|state| {
let fail = state.get();
if fail {
state.set(false);
}
fail
}) {
return Err(Error::new(ErrorKind::InvalidData, "copied item count overflows u64"));
}
copied
.checked_add(count as u64)
.ok_or_else(|| Error::new(ErrorKind::InvalidData, "copied item count overflows u64"))
}
#[cfg(coverage)]
#[doc(hidden)]
#[inline(always)]
pub fn coverage_add_item_count_overflow() -> Result<u64> {
add_item_count(u64::MAX, 1)
}