use std::cmp::Ordering;
use std::io::{
Error,
ErrorKind,
Read,
Result,
Write,
};
use crate::ReadExt;
use crate::capacity_const::{
DEFAULT_COMPARE_BUFFER_SIZE,
DEFAULT_COPY_BUFFER_SIZE,
};
use crate::util::create_vec;
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);
}
}
}
}
#[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)
}