use std::io::{
Error,
ErrorKind,
Read,
Result,
Write,
copy as copy_all,
};
use std::string::FromUtf8Error;
use crate::Streams;
const DISCARD_BUFFER_SIZE: usize = 8 * 1024;
const READ_TO_END_BUFFER_SIZE: usize = 8 * 1024;
pub trait ReadExt: Read {
fn read_exact_or_eof(&mut self, buffer: &mut [u8]) -> Result<usize>;
fn read_exact_array<const N: usize>(&mut self) -> Result<[u8; N]>;
fn read_exact_vec_limited(&mut self, len: usize, max_len: usize) -> Result<Vec<u8>>;
fn read_exact_vec_limited_into(
&mut self,
output: &mut Vec<u8>,
len: usize,
max_len: usize,
) -> Result<()>;
fn discard_exact_or_eof(&mut self, bytes: u64) -> Result<u64>;
fn copy_to(&mut self, writer: &mut dyn Write) -> Result<u64>;
fn copy_to_at_most(&mut self, writer: &mut dyn Write, max_bytes: u64) -> Result<u64>;
fn copy_to_end_limited(&mut self, writer: &mut dyn Write, max_bytes: u64) -> Result<u64>;
fn read_to_end_limited(&mut self, max_len: usize) -> Result<Vec<u8>>;
fn read_to_end_limited_into(&mut self, output: &mut Vec<u8>, max_len: usize) -> Result<usize>;
fn read_to_string_limited(&mut self, max_len: usize) -> Result<String>;
fn read_to_string_limited_into(&mut self, output: &mut String, max_len: usize)
-> Result<usize>;
}
impl<T> ReadExt for T
where
T: Read + ?Sized,
{
#[inline]
fn read_exact_or_eof(&mut self, buffer: &mut [u8]) -> Result<usize> {
let mut reader = self;
read_exact_or_eof_impl(&mut reader, buffer)
}
#[inline]
fn read_exact_array<const N: usize>(&mut self) -> Result<[u8; N]> {
let mut reader = self;
read_exact_array_impl::<N>(&mut reader)
}
#[inline]
fn read_exact_vec_limited(&mut self, len: usize, max_len: usize) -> Result<Vec<u8>> {
let mut reader = self;
read_exact_vec_limited_impl(&mut reader, len, max_len)
}
#[inline]
fn read_exact_vec_limited_into(
&mut self,
output: &mut Vec<u8>,
len: usize,
max_len: usize,
) -> Result<()> {
let mut reader = self;
read_exact_vec_limited_into_impl(&mut reader, output, len, max_len)
}
#[inline]
fn discard_exact_or_eof(&mut self, bytes: u64) -> Result<u64> {
let mut reader = self;
discard_exact_or_eof_impl(&mut reader, bytes)
}
#[inline]
fn copy_to(&mut self, writer: &mut dyn Write) -> Result<u64> {
let mut reader = self;
copy_to_impl(&mut reader, writer)
}
#[inline]
fn copy_to_at_most(&mut self, writer: &mut dyn Write, max_bytes: u64) -> Result<u64> {
let mut reader = self;
Streams::copy_at_most(&mut reader, writer, max_bytes)
}
#[inline]
fn copy_to_end_limited(&mut self, writer: &mut dyn Write, max_bytes: u64) -> Result<u64> {
let mut reader = self;
Streams::copy_to_end_limited(&mut reader, writer, max_bytes)
}
#[inline]
fn read_to_end_limited(&mut self, max_len: usize) -> Result<Vec<u8>> {
let mut reader = self;
read_to_end_limited_impl(&mut reader, max_len)
}
#[inline]
fn read_to_end_limited_into(&mut self, output: &mut Vec<u8>, max_len: usize) -> Result<usize> {
let mut reader = self;
read_to_end_limited_into_impl(&mut reader, output, max_len)
}
#[inline]
fn read_to_string_limited(&mut self, max_len: usize) -> Result<String> {
let mut reader = self;
read_to_string_limited_impl(&mut reader, max_len)
}
#[inline]
fn read_to_string_limited_into(
&mut self,
output: &mut String,
max_len: usize,
) -> Result<usize> {
let mut reader = self;
read_to_string_limited_into_impl(&mut reader, output, max_len)
}
}
fn read_exact_or_eof_impl(reader: &mut dyn Read, buffer: &mut [u8]) -> Result<usize> {
let mut total = 0;
while total < buffer.len() {
match reader.read(&mut buffer[total..]) {
Ok(0) => break,
Ok(count) => total += count,
Err(error) => {
if error.kind() == ErrorKind::Interrupted {
continue;
}
return Err(error);
}
}
}
Ok(total)
}
fn read_exact_array_impl<const N: usize>(reader: &mut dyn Read) -> Result<[u8; N]> {
let mut buffer = [0; N];
reader.read_exact(&mut buffer)?;
Ok(buffer)
}
fn read_exact_vec_limited_impl(
reader: &mut dyn Read,
len: usize,
max_len: usize,
) -> Result<Vec<u8>> {
validate_exact_read_len(len, max_len)?;
let mut output = Vec::with_capacity(len);
read_exact_vec_limited_into_impl(reader, &mut output, len, max_len)?;
Ok(output)
}
fn read_exact_vec_limited_into_impl(
reader: &mut dyn Read,
output: &mut Vec<u8>,
len: usize,
max_len: usize,
) -> Result<()> {
validate_exact_read_len(len, max_len)?;
let original_len = output.len();
output.resize(original_len + len, 0);
match reader.read_exact(&mut output[original_len..]) {
Ok(()) => Ok(()),
Err(error) => {
output.truncate(original_len);
Err(error)
}
}
}
fn validate_exact_read_len(len: usize, max_len: usize) -> Result<()> {
if len > max_len {
return Err(Error::new(
ErrorKind::InvalidData,
format!("requested length {len} exceeds maximum length {max_len}"),
));
}
Ok(())
}
fn discard_exact_or_eof_impl(reader: &mut dyn Read, bytes: u64) -> Result<u64> {
let mut buffer = [0; DISCARD_BUFFER_SIZE];
let mut remaining = bytes;
let mut discarded = 0;
while remaining > 0 {
let requested = remaining.min(DISCARD_BUFFER_SIZE as u64) as usize;
match reader.read(&mut buffer[..requested]) {
Ok(0) => break,
Ok(count) => {
let count = count as u64;
remaining -= count;
discarded += count;
}
Err(error) => {
if error.kind() == ErrorKind::Interrupted {
continue;
}
return Err(error);
}
}
}
Ok(discarded)
}
fn read_to_end_limited_impl(reader: &mut dyn Read, max_len: usize) -> Result<Vec<u8>> {
let mut output = Vec::with_capacity(max_len.min(READ_TO_END_BUFFER_SIZE));
read_to_end_limited_into_impl(reader, &mut output, max_len)?;
Ok(output)
}
fn read_to_end_limited_into_impl(
reader: &mut dyn Read,
output: &mut Vec<u8>,
max_len: usize,
) -> Result<usize> {
let mut buffer = [0; READ_TO_END_BUFFER_SIZE];
let mut appended = 0;
loop {
let remaining = max_len.saturating_sub(appended);
let requested = remaining.saturating_add(1).min(READ_TO_END_BUFFER_SIZE);
match reader.read(&mut buffer[..requested]) {
Ok(0) => return Ok(appended),
Ok(count) if count <= remaining => {
output.extend_from_slice(&buffer[..count]);
appended += count;
}
Ok(_) => {
if remaining > 0 {
output.extend_from_slice(&buffer[..remaining]);
}
return Err(Error::new(
ErrorKind::InvalidData,
format!("input exceeds maximum length of {max_len} bytes"),
));
}
Err(error) => {
if error.kind() == ErrorKind::Interrupted {
continue;
}
return Err(error);
}
}
}
}
fn read_to_string_limited_impl(reader: &mut dyn Read, max_len: usize) -> Result<String> {
let bytes = read_to_end_limited_impl(reader, max_len)?;
String::from_utf8(bytes).map_err(invalid_utf8_error)
}
fn read_to_string_limited_into_impl(
reader: &mut dyn Read,
output: &mut String,
max_len: usize,
) -> Result<usize> {
let bytes = read_to_end_limited_impl(reader, max_len)?;
let text = String::from_utf8(bytes).map_err(invalid_utf8_error)?;
let count = text.len();
output.push_str(&text);
Ok(count)
}
fn copy_to_impl(reader: &mut dyn Read, writer: &mut dyn Write) -> Result<u64> {
copy_all(reader, writer)
}
fn invalid_utf8_error(error: FromUtf8Error) -> Error {
Error::new(
ErrorKind::InvalidData,
format!("limited input is not valid UTF-8: {error}"),
)
}