use std::cmp::Ordering;
use std::io::{
Error,
ErrorKind,
Read,
Result,
Write,
copy,
};
use crate::ReadExt;
const COPY_BUFFER_SIZE: usize = 16 * 1024;
const COMPARE_BUFFER_SIZE: usize = 16 * 1024;
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,
{
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)
}
#[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;
copy_to_end_limited_impl(&mut reader, &mut writer, max_bytes)
}
#[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> {
let mut left_buffer = [0; COMPARE_BUFFER_SIZE];
let mut right_buffer = [0; COMPARE_BUFFER_SIZE];
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) -> Result<u64> {
let mut buffer = [0; COPY_BUFFER_SIZE];
let mut remaining = max_bytes;
let mut copied = 0;
while remaining > 0 {
let requested = remaining.min(COPY_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)?;
if copied < max_bytes {
return Ok(copied);
}
if has_more_input(reader)? {
return Err(Error::new(
ErrorKind::InvalidData,
format!("input exceeds maximum length of {max_bytes} bytes"),
));
}
Ok(copied)
}
fn has_more_input(reader: &mut dyn Read) -> Result<bool> {
let mut byte = [0];
loop {
match reader.read(&mut byte) {
Ok(0) => return Ok(false),
Ok(_) => return Ok(true),
Err(error) => {
if error.kind() == ErrorKind::Interrupted {
continue;
}
return Err(error);
}
}
}
}