use super::{RecvError, SendError};
use std::io;
const IOBUF_SIZE: usize = 4096;
pub struct IOBuf {
buf: [u8; IOBUF_SIZE],
start: usize,
end: usize,
}
impl IOBuf {
pub fn new() -> IOBuf {
IOBuf {
buf: [0; IOBUF_SIZE],
start: 0,
end: 0,
}
}
pub fn empty(&self) -> bool {
self.start == self.end
}
pub fn size(&self) -> usize {
self.end - self.start
}
pub fn data(&self) -> &[u8] {
&self.buf[self.start..self.end]
}
pub fn consume(&mut self, len: usize) {
if len > self.size() {
panic!("Invalid consume for more data that is contained");
}
self.start += len;
}
pub fn flush(&mut self) {
self.start = 0;
self.end = 0;
}
fn compact(&mut self) {
if self.start != 0 {
let len = self.size();
self.buf.copy_within(self.start..self.end, 0);
self.start = 0;
self.end = len;
}
}
pub fn refill<T: io::Read>(&mut self, reader: &mut T) -> Result<(), RecvError> {
self.compact();
match reader.read(&mut self.buf[self.end..]) {
Ok(size) => {
if size > 0 {
self.end += size;
Ok(())
} else {
Err(RecvError::Disconnected)
}
}
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
Err(RecvError::NotReady)
} else {
Err(RecvError::IO(e))
}
}
}
}
pub fn add_data(&mut self, data: &[u8]) -> Result<(), usize> {
self.compact();
let copy_size = std::cmp::min(IOBUF_SIZE - self.end, data.len());
self.buf[self.end..self.end + copy_size].copy_from_slice(&data[0..copy_size]);
self.end += copy_size;
if copy_size == data.len() {
Ok(())
} else {
Err(copy_size)
}
}
pub fn drain<T: io::Write>(&mut self, writer: &mut T) -> Result<(), SendError> {
if self.end > self.start {
match writer.write(&self.buf[self.start..self.end]) {
Ok(size) => {
self.consume(size);
if self.empty() {
Ok(())
} else {
Err(SendError::MustDrain)
}
}
Err(e) => {
if e.kind() == io::ErrorKind::WouldBlock {
Err(SendError::MustDrain)
} else {
Err(SendError::IO(e))
}
}
}
} else {
Ok(())
}
}
}