use crate::{BufRead, Read, Result};
#[cfg(feature = "alloc")]
use alloc::{string::String, vec::Vec};
const DEFAULT_BUF_SIZE: usize = 1024;
pub struct BufReader<R> {
inner: R,
pos: usize,
filled: usize,
buf: [u8; DEFAULT_BUF_SIZE],
}
impl<R: Read> BufReader<R> {
pub const fn new(inner: R) -> BufReader<R> {
Self {
inner,
pos: 0,
filled: 0,
buf: [0; DEFAULT_BUF_SIZE],
}
}
}
impl<R> BufReader<R> {
pub const fn get_ref(&self) -> &R {
&self.inner
}
pub fn get_mut(&mut self) -> &mut R {
&mut self.inner
}
pub fn buffer(&self) -> &[u8] {
&self.buf[self.pos..self.filled]
}
pub const fn capacity(&self) -> usize {
DEFAULT_BUF_SIZE
}
pub fn into_inner(self) -> R {
self.inner
}
fn discard_buffer(&mut self) {
self.pos = 0;
self.filled = 0;
}
const fn is_empty(&self) -> bool {
self.pos >= self.filled
}
}
impl<R: Read> Read for BufReader<R> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
if self.is_empty() && buf.len() >= self.capacity() {
self.discard_buffer();
return self.inner.read(buf);
}
let nread = {
let mut rem = self.fill_buf()?;
rem.read(buf)?
};
self.consume(nread);
Ok(nread)
}
fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> {
let amt = buf.len();
if let Some(claimed) = self.buffer().get(..amt) {
buf.copy_from_slice(claimed);
self.pos += amt;
return Ok(());
}
self.inner.read_exact(buf)
}
#[cfg(feature = "alloc")]
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
let inner_buf = self.buffer();
buf.extend_from_slice(inner_buf);
let nread = inner_buf.len();
self.discard_buffer();
Ok(nread + self.inner.read_to_end(buf)?)
}
#[cfg(feature = "alloc")]
fn read_to_string(&mut self, buf: &mut String) -> Result<usize> {
if buf.is_empty() {
unsafe { crate::append_to_string(buf, |b| self.read_to_end(b)) }
} else {
let mut bytes = Vec::new();
self.read_to_end(&mut bytes)?;
let string = core::str::from_utf8(&bytes).map_err(|_| {
axerrno::ax_err_type!(InvalidData, "stream did not contain valid UTF-8")
})?;
*buf += string;
Ok(string.len())
}
}
}
impl<R: Read> BufRead for BufReader<R> {
fn fill_buf(&mut self) -> Result<&[u8]> {
if self.is_empty() {
let read_len = self.inner.read(&mut self.buf)?;
self.pos = 0;
self.filled = read_len;
}
Ok(self.buffer())
}
fn consume(&mut self, amt: usize) {
self.pos = core::cmp::min(self.pos + amt, self.filled);
}
}