use crate::compat;
use crate::errors;
use crate::io as ggio;
use std::io::Write;
pub(crate) const DEFAULT_BUF_SIZE: usize = 4096;
static ERR_BUFFER_FULL: errors::ErrorStaticString = errors::new_static("bufio: buffer full");
pub struct Reader<'a, Input: std::io::Read> {
buf: Vec<u8>,
rd: &'a mut Input, r: usize, w: usize, err: Option<Box<dyn std::error::Error>>,
last_byte: isize, last_rune_size: isize, }
const MIN_READ_BUFFER_SIZE: usize = 16;
pub(super) const MAX_CONSECUTIVE_EMPTY_READS: usize = 100;
impl<'a, Input: std::io::Read> Reader<'a, Input> {
pub fn new(r: &'a mut Input) -> Self {
Self::new_size(r, DEFAULT_BUF_SIZE)
}
pub fn new_size(r: &'a mut Input, size: usize) -> Self {
let size = size.max(MIN_READ_BUFFER_SIZE);
Reader {
buf: vec![0; size],
rd: r,
r: 0,
w: 0,
err: None,
last_byte: -1,
last_rune_size: -1,
}
}
pub fn size(&mut self) -> usize {
self.buf.len()
}
pub fn reset(&mut self, r: &'a mut Input) {
self.buf.resize(DEFAULT_BUF_SIZE, 0);
self.rd = r;
self.r = 0;
self.w = 0;
self.last_byte = -1;
self.last_rune_size = -1;
}
fn fill(&mut self) {
if self.r > 0 {
self.buf.copy_within(self.r..self.w, 0);
self.w -= self.r;
self.r = 0
}
if self.w >= self.buf.len() {
panic!("bufio: tried to fill full buffer");
}
for _i in 0..MAX_CONSECUTIVE_EMPTY_READS {
let res = self.rd.read(&mut self.buf[self.w..]);
match res {
Err(err) => {
self.err = Some(Box::new(err));
return;
}
Ok(n) => {
self.w += n;
if n > 0 {
return;
}
}
}
}
self.err = Some(Box::new(ggio::err_no_progress()));
}
fn read_err(&mut self) -> Option<Box<dyn std::error::Error>> {
self.err.take()
}
pub fn peek(&mut self, n: usize) -> (&[u8], Option<Box<dyn std::error::Error>>) {
self.last_byte = -1;
self.last_rune_size = -1;
while self.w - self.r < n && self.w - self.r < self.buf.len() && self.err.is_none() {
self.fill(); }
if n > self.buf.len() {
return (&self.buf[self.r..self.w], Some(Box::new(ERR_BUFFER_FULL)));
}
let mut err = None;
let avail = self.w - self.r;
let mut n = n;
if avail < n {
n = avail;
err = self.read_err();
if err.is_none() {
err = Some(Box::new(ERR_BUFFER_FULL));
}
}
(&self.buf[self.r..self.r + n], err)
}
pub fn buffered(&mut self) -> usize {
self.w - self.r
}
}
pub struct Writer<'a> {
err: Option<std::io::Error>,
buf: Vec<u8>,
n: usize,
wr: &'a mut dyn std::io::Write,
}
impl std::io::Write for Writer<'_> {
fn write(&mut self, p: &[u8]) -> std::io::Result<usize> {
if self.err.is_some() {
return Err(errors::copy_stdio_error(self.err.as_ref().unwrap()));
}
let mut p = p;
let mut nn = 0;
while p.len() > self.available() && self.err.is_none() {
let mut n = 0;
if self.buffered() == 0 {
match self.wr.write(p) {
Ok(nw) => n = nw,
Err(err) => self.err = Some(err),
}
} else {
n = compat::copy(&mut self.buf[self.n..], p);
self.n += n;
_ = self.flush();
}
nn += n;
p = &p[n..];
}
if self.err.is_some() {
if nn > 0 {
return Ok(nn);
}
return Err(errors::copy_stdio_error(self.err.as_ref().unwrap()));
}
let n = compat::copy(&mut self.buf[self.n..], p);
self.n += n;
nn += n;
Ok(nn)
}
fn flush(&mut self) -> std::io::Result<()> {
if self.err.is_some() {
return Err(errors::copy_stdio_error(self.err.as_ref().unwrap()));
}
if self.n == 0 {
return Ok(());
}
match self.wr.write(&self.buf[0..self.n]) {
Err(err) => {
self.err = Some(err);
return Err(errors::copy_stdio_error(self.err.as_ref().unwrap()));
}
Ok(n) => {
if n > 0 && n < self.n {
compat::copy_within(&mut self.buf, n..self.n, 0);
}
self.n -= n;
}
}
if self.n > 0 {
self.err = Some(ggio::new_error_short_write());
return Err(errors::copy_stdio_error(self.err.as_ref().unwrap()));
}
Ok(())
}
}
impl<'a> Writer<'a> {
pub fn new(w: &'a mut dyn std::io::Write) -> Self {
Self::new_size(w, DEFAULT_BUF_SIZE)
}
pub fn new_size(w: &'a mut dyn std::io::Write, size: usize) -> Self {
Self {
err: None,
buf: vec![0; if size == 0 { DEFAULT_BUF_SIZE } else { size }],
n: 0,
wr: w,
}
}
pub fn size(&self) -> usize {
self.buf.len()
}
pub fn reset(&mut self, w: &'a mut dyn std::io::Write) {
self.err = None;
self.n = 0;
self.wr = w;
}
pub fn available(&self) -> usize {
self.buf.len() - self.n
}
fn buffered(&self) -> usize {
self.n
}
pub fn write_byte(&mut self, c: u8) -> std::io::Result<()> {
if self.err.is_some() {
return Err(errors::copy_stdio_error(self.err.as_ref().unwrap()));
}
if self.available() == 0 && self.flush().is_err() {
return Err(errors::copy_stdio_error(self.err.as_ref().unwrap()));
}
self.buf[self.n] = c;
self.n += 1;
Ok(())
}
pub fn write_string(&mut self, s: &str) -> std::io::Result<usize> {
self.write(s.as_bytes())
}
}