use super::Buffer;
#[derive(Copy, Clone, Debug)]
pub struct DoRead(pub bool);
#[macro_export]
macro_rules! do_read (
($val:expr) => ( return $crate::policy::DoRead($val); );
() => ( do_read!(true); )
);
#[derive(Debug, Default)]
pub struct StdPolicy;
pub trait ReaderPolicy {
fn before_read(&mut self, buffer: &mut Buffer) -> DoRead { DoRead(buffer.len() == 0) }
fn after_consume(&mut self, _buffer: &mut Buffer, _amt: usize) {}
}
impl ReaderPolicy for StdPolicy {}
#[derive(Debug)]
pub struct MinBuffered(pub usize);
impl MinBuffered {
pub fn set_min(&mut self, min: usize) {
self.0 = min;
}
}
impl ReaderPolicy for MinBuffered {
fn before_read(&mut self, buffer: &mut Buffer) -> DoRead {
if buffer.len() >= self.0 { do_read!(false) }
let cap = buffer.capacity();
if buffer.usable_space() < self.0 && buffer.free_space() >= self.0 {
buffer.make_room();
} else if cap < self.0 {
buffer.reserve(self.0 - cap);
}
DoRead(true)
}
}
#[derive(Copy, Clone, Debug)]
pub struct FlushAmt(pub usize);
#[macro_export]
macro_rules! flush_amt (
($n:expr) => ( return $crate::policy::FlushAmt($n); );
() => ( flush_amt!(0); )
);
pub trait WriterPolicy {
fn before_write(&mut self, buf: &mut Buffer, incoming: usize) -> FlushAmt {
FlushAmt(if incoming > buf.usable_space() { buf.len() } else { 0 })
}
fn after_write(&mut self, _buf: &Buffer) -> FlushAmt {
FlushAmt(0)
}
}
impl WriterPolicy for StdPolicy {}
#[derive(Debug, Default)]
pub struct FlushAtLeast(pub usize);
impl WriterPolicy for FlushAtLeast {
fn before_write(&mut self, buf: &mut Buffer, incoming: usize) -> FlushAmt {
ensure_capacity(buf, self.0);
FlushAmt(if incoming > buf.usable_space() { buf.len() } else { 0 })
}
fn after_write(&mut self, buf: &Buffer) -> FlushAmt {
FlushAmt(::std::cmp::max(buf.len(), self.0))
}
}
#[derive(Debug, Default)]
pub struct FlushExact(pub usize);
impl WriterPolicy for FlushExact {
fn before_write(&mut self, buf: &mut Buffer, incoming: usize) -> FlushAmt {
ensure_capacity(buf, self.0);
if incoming > buf.usable_space() && buf.len() < self.0 {
buf.make_room();
}
FlushAmt(self.0)
}
fn after_write(&mut self, _buf: &Buffer) -> FlushAmt {
FlushAmt(self.0)
}
}
#[derive(Debug, Default)]
pub struct FlushOn(pub u8);
impl WriterPolicy for FlushOn {
fn after_write(&mut self, buf: &Buffer) -> FlushAmt {
FlushAmt(::memchr::memrchr(self.0, buf.buf()).map_or(0, |n| n + 1))
}
}
#[derive(Debug, Default)]
pub struct FlushOnNewline;
impl WriterPolicy for FlushOnNewline {
fn after_write(&mut self, buf: &Buffer) -> FlushAmt {
FlushAmt(::memchr::memrchr(b'\n', buf.buf()).map_or(0, |n| n + 1))
}
}
fn ensure_capacity(buf: &mut Buffer, min_cap: usize) {
let cap = buf.capacity();
if cap < min_cap {
buf.reserve(min_cap - cap);
}
}
#[cfg(test)]
mod test {
use {BufReader, BufWriter};
use policy::*;
use std::io::{BufRead, Cursor, Write};
#[test]
fn test_min_buffered() {
let min_buffered = 4;
let data = (0 .. 20).collect::<Vec<u8>>();
let mut reader = BufReader::with_capacity(0, Cursor::new(data))
.set_policy(MinBuffered(min_buffered));
assert_eq!(reader.fill_buf().unwrap(), &[0, 1, 2, 3][..]);
assert_eq!(reader.capacity(), min_buffered);
reader.reserve(min_buffered);
assert_eq!(reader.capacity(), min_buffered * 2);
assert_eq!(reader.fill_buf().unwrap(), &[0, 1, 2, 3]);
reader.consume(2);
assert_eq!(reader.fill_buf().unwrap(), &[2, 3, 4, 5, 6, 7]);
reader.consume(4);
assert_eq!(reader.fill_buf().unwrap(), &[6, 7, 8, 9, 10, 11, 12, 13]);
reader.consume(4);
assert_eq!(reader.fill_buf().unwrap(), &[10, 11, 12, 13]);
reader.consume(2);
assert_eq!(reader.fill_buf().unwrap(), &[12, 13, 14, 15, 16, 17, 18, 19]);
reader.consume(8);
assert_eq!(reader.fill_buf().unwrap(), &[])
}
#[test]
fn test_flush_at_least() {
let flush_min = 4;
let mut writer = BufWriter::with_capacity(0, vec![]).set_policy(FlushAtLeast(flush_min));
assert_eq!(writer.capacity(), 0);
assert_eq!(writer.write(&[1]).unwrap(), 1);
assert_eq!(writer.capacity(), flush_min);
writer.reserve(flush_min * 2 - 1);
assert_eq!(writer.capacity(), flush_min * 2);
assert_eq!(writer.write(&[2, 3]).unwrap(), 2);
assert_eq!(*writer.get_ref(), &[]);
assert_eq!(writer.write(&[4, 5, 6]).unwrap(), 3);
assert_eq!(*writer.get_ref(), &[1, 2, 3, 4, 5, 6]);
assert_eq!(writer.write(&[7, 8, 9]).unwrap(), 3);
assert_eq!(writer.into_inner().unwrap(), &[1, 2, 3, 4, 5, 6, 7, 8, 9]);
}
#[test]
fn test_flush_exact() {
let flush_exact = 4;
let mut writer = BufWriter::with_capacity(0, vec![]).set_policy(FlushExact(flush_exact));
assert_eq!(writer.capacity(), 0);
assert_eq!(writer.write(&[1]).unwrap(), 1);
assert_eq!(writer.capacity(), flush_exact);
writer.reserve(flush_exact * 2 - 1);
assert_eq!(writer.capacity(), flush_exact * 2);
assert_eq!(writer.write(&[2, 3]).unwrap(), 2);
assert_eq!(*writer.get_ref(), &[]);
assert_eq!(writer.write(&[4, 5, 6]).unwrap(), 3);
assert_eq!(*writer.get_ref(), &[1, 2, 3, 4]);
assert_eq!(writer.write(&[7, 8, 9, 10]).unwrap(), 4);
assert_eq!(*writer.get_ref(), &[1, 2, 3, 4, 5, 6, 7, 8]);
assert_eq!(writer.into_inner().unwrap(), &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
}
#[test]
fn test_flush_on() {
let mut writer = BufWriter::with_capacity(8, vec![]).set_policy(FlushOn(0));
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(*writer.get_ref(), &[]);
assert_eq!(writer.write(&[0, 4, 5]).unwrap(), 3);
assert_eq!(*writer.get_ref(), &[1, 2, 3, 0]);
assert_eq!(writer.write(&[6, 7, 8, 9, 10, 11, 12]).unwrap(), 7);
assert_eq!(*writer.get_ref(), &[1, 2, 3, 0, 4, 5]);
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(*writer.get_ref(), &[1, 2, 3, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0]);
}
#[test]
fn test_flush_on_newline() {
let mut writer = BufWriter::with_capacity(8, vec![]).set_policy(FlushOnNewline);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(*writer.get_ref(), &[]);
assert_eq!(writer.write(&[b'\n', 4, 5]).unwrap(), 3);
assert_eq!(*writer.get_ref(), &[1, 2, 3, b'\n']);
assert_eq!(writer.write(&[6, 7, 8, 9, b'\n', 11, 12]).unwrap(), 7);
assert_eq!(*writer.get_ref(), &[1, 2, 3, b'\n', 4, 5, 6, 7, 8, 9, b'\n']);
assert_eq!(writer.write(&[b'\n']).unwrap(), 1);
assert_eq!(*writer.get_ref(), &[1, 2, 3, b'\n', 4, 5, 6, 7, 8, 9, b'\n', 11, 12, b'\n']);
}
}