#[cfg(coverage)]
use std::cell::Cell;
use std::cmp::Ordering;
use std::io::{
Error,
ErrorKind,
Read,
Result,
Write,
};
use crate::ReadExt;
use crate::capacity_const::{
DEFAULT_BUFFER_CAPACITY,
DEFAULT_COMPARE_BUFFER_SIZE,
DEFAULT_COPY_BUFFER_SIZE,
};
use crate::traits::validate_read_count;
use crate::util::{
create_vec,
try_reserve_vec,
};
use crate::{
Input,
Output,
};
pub enum Streams {}
impl Streams {
#[inline]
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]
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]
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]
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;
let copied = copy_at_most_impl(
&mut reader,
&mut 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);
}
}
}
}
pub fn copy_input_to_output<I, O>(
input: &mut I,
output: &mut O,
) -> Result<u64>
where
I: Input + ?Sized,
O: Output<Item = I::Item> + ?Sized,
I::Item: Copy + Default,
{
let mut buffer =
create_vec(DEFAULT_BUFFER_CAPACITY, I::Item::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<I, O>(
input: &mut I,
output: &mut O,
max_items: u64,
) -> Result<u64>
where
I: Input + ?Sized,
O: Output<Item = I::Item> + ?Sized,
I::Item: Copy + Default,
{
if max_items == 0 {
return Ok(0);
}
let mut buffer =
create_vec(DEFAULT_BUFFER_CAPACITY, I::Item::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<I, O>(
input: &mut I,
output: &mut O,
max_items: u64,
) -> Result<u64>
where
I: Input + ?Sized,
O: Output<Item = I::Item> + ?Sized,
I::Item: Copy + Default,
{
let mut buffer =
create_vec(DEFAULT_BUFFER_CAPACITY, I::Item::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)?;
collected.extend_from_slice(&buffer[..read]);
let read = read as u64;
remaining -= read;
copied = add_item_count(copied, read as usize)?;
}
}
#[inline]
pub fn content_eq(
left: &mut dyn Read,
right: &mut dyn Read,
) -> Result<bool> {
Ok(Self::compare_content(left, right)? == Ordering::Equal)
}
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);
for index in 0..n {
match left_buffer[index].cmp(&right_buffer[index]) {
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",
));
}
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)
}
#[cfg(coverage)]
thread_local! {
static COVERAGE_FAIL_NEXT_ADD_ITEM_COUNT: Cell<bool> = const { Cell::new(false) };
}
#[cfg(coverage)]
#[doc(hidden)]
pub fn coverage_fail_next_add_item_count() {
COVERAGE_FAIL_NEXT_ADD_ITEM_COUNT.with(|state| state.set(true));
}
#[cfg(coverage)]
#[doc(hidden)]
pub fn coverage_reset_add_item_count_hooks() {
COVERAGE_FAIL_NEXT_ADD_ITEM_COUNT.with(|state| state.set(false));
}
#[inline(always)]
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)]
pub fn coverage_add_item_count_overflow() -> Result<u64> {
add_item_count(u64::MAX, 1)
}