use std::io::BufRead;
use std::io::Error;
use std::io::ErrorKind;
use std::io::Result;
use crate::std_io::ext::internal::read_ext_impl;
use crate::util::allocation_error;
use crate::util::try_reserve_string;
use crate::util::try_reserve_vec;
pub trait BufReadExt: BufRead {
fn read_until_limited(&mut self, delimiter: u8, max_len: usize) -> Result<Vec<u8>>;
fn read_until_limited_into(&mut self, delimiter: u8, output: &mut Vec<u8>, max_len: usize) -> Result<usize>;
fn read_line_limited(&mut self, max_len: usize) -> Result<String>;
fn read_line_limited_into(&mut self, output: &mut String, max_len: usize) -> Result<usize>;
fn discard_until_limited(&mut self, delimiter: u8, max_len: usize) -> Result<usize>;
}
impl<T> BufReadExt for T
where
T: BufRead + ?Sized,
{
#[inline]
fn read_until_limited(&mut self, delimiter: u8, max_len: usize) -> Result<Vec<u8>> {
let mut output = Vec::new();
try_reserve_vec(&mut output, max_len.min(8192)).map_err(allocation_error)?;
read_ext_impl::read_until_limited_into(self, delimiter, &mut output, max_len)?;
Ok(output)
}
#[inline(always)]
fn read_until_limited_into(&mut self, delimiter: u8, output: &mut Vec<u8>, max_len: usize) -> Result<usize> {
read_ext_impl::read_until_limited_into(self, delimiter, output, max_len)
}
#[inline]
fn read_line_limited(&mut self, max_len: usize) -> Result<String> {
let mut output = String::new();
self.read_line_limited_into(&mut output, max_len)?;
Ok(output)
}
fn read_line_limited_into(&mut self, output: &mut String, max_len: usize) -> Result<usize> {
let original_len = output.len();
let mut bytes = Vec::new();
try_reserve_vec(&mut bytes, max_len.min(8192)).map_err(allocation_error)?;
let result = (|| {
let count = read_ext_impl::read_until_limited_into(self, b'\n', &mut bytes, max_len)?;
let line = String::from_utf8(bytes).map_err(|error| {
Error::new(
ErrorKind::InvalidData,
format!("limited line is not valid UTF-8: {error}"),
)
})?;
try_reserve_string(output, line.len()).map_err(allocation_error)?;
output.push_str(&line);
Ok(count)
})();
if result.is_err() {
output.truncate(original_len);
}
result
}
fn discard_until_limited(&mut self, delimiter: u8, max_len: usize) -> Result<usize> {
let mut discarded = 0;
loop {
let available = self.fill_buf()?;
if available.is_empty() {
return Ok(discarded);
}
let delimiter_position = available.iter().position(|byte| *byte == delimiter);
let requested = delimiter_position.map_or(available.len(), |position| position + 1);
let remaining = max_len.saturating_sub(discarded);
if requested > remaining {
if remaining > 0 {
self.consume(remaining);
}
return Err(Error::new(
ErrorKind::InvalidData,
format!("input exceeds maximum length of {max_len} bytes before delimiter {delimiter}"),
));
}
self.consume(requested);
discarded += requested;
if delimiter_position.is_some() {
return Ok(discarded);
}
}
}
}