use super::{ConvertSlice, ErrHandler, Reader};
#[allow(unused_imports)] use opts;
use results::{Result, Success};
use std::{
cmp::Ordering,
io::{BufRead, Read, Write},
time::SystemTime,
};
pub fn standard<R, W, C, E>(mut r: Reader<R>, w: &mut W, c: C, mut e: ErrHandler<E>) -> Result<Success>
where
R: Read,
W: Write,
C: ConvertSlice<u8>,
E: Write,
{
let start = SystemTime::now();
let mut bytes = 0;
loop {
let converted = match e.handle(r.fill_buf())? {
Some(ref buf) if buf.len() == 0 => return Ok(Success::Bytes { bytes, start }),
Some(buf) => c.convert_copy(buf),
None => continue,
};
e.handle(w.write_all(&converted))?;
r.consume(converted.len());
bytes += converted.len();
e.report_status_standard(bytes, &start)?
}
}
pub fn bytes<R, W, C, E>(mut r: R, w: &mut W, c: &C, mut e: ErrHandler<E>, max_bytes: usize) -> Result<Success>
where
R: BufRead,
W: Write,
C: ConvertSlice<u8>,
E: Write,
{
let start = SystemTime::now();
let mut bytes = 0;
loop {
let converted = match e.handle(r.fill_buf())? {
None => continue,
Some(buf) => match usize::min(max_bytes.saturating_sub(bytes), buf.len()) {
0 => return Ok(Success::Bytes { bytes, start }),
n => c.convert_copy(&buf[..n]),
},
};
e.handle(w.write_all(&converted))?;
r.consume(converted.len());
bytes += converted.len();
}
}
pub fn block<R, W, C, E>(r: R, w: &mut W, c: C, mut e: ErrHandler<E>, block_size: usize) -> Result<Success>
where
R: BufRead,
W: Write,
C: ConvertSlice<u8>,
E: Write,
{
let (mut lines, mut padded, mut truncated): (usize, usize, usize) = (0, 0, 0);
let (mut buf, mut bytes): (Vec<u8>, std::io::Bytes<_>) = (Vec::with_capacity(block_size), r.bytes());
let start = SystemTime::now();
while {
if let Some(b) = skip_trailing_while_match(&mut bytes, &b'\n')? {
buf.push(b)
};
e.handle(fill_buf_until_match(&mut bytes, &mut buf, b'\n'))?;
buf.len() != 0
} {
lines += 1;
match buf.len().cmp(&block_size) {
Ordering::Greater => truncated += 1,
Ordering::Less => padded += 1,
Ordering::Equal => {},
}
c.convert_slice(&mut buf);
buf.resize(block_size, b' ');
w.write_all(&buf)?;
e.report_status_block(lines, &start);
buf.clear();
}
Ok(Success::Block {
start,
lines,
truncated,
padded,
block_size,
})
}
pub fn unblock<R, W, C, E>(r: R, w: &mut W, c: C, mut e: ErrHandler<E>, block_size: usize) -> Result<Success>
where
R: BufRead,
W: Write,
C: ConvertSlice<u8>,
E: Write,
{
let start = SystemTime::now();
let mut buf: Vec<u8> = Vec::with_capacity(block_size + 1); let mut bytes = r.bytes();
let mut blocks = 0;
while {
if let Some(Some(b)) = e.handle(skip_trailing_while_match(&mut bytes, &b' '))? {
buf.push(b)
};
fill_buf_to(&mut bytes, &mut buf, block_size)?;
buf.len() != 0
} {
buf.push(b'\n');
c.convert_slice(&mut buf);
e.handle(w.write_all(&mut buf))?;
blocks += 1;
e.report_status_unblock(blocks, &start);
buf.clear();
}
Ok(Success::Unblock {
blocks,
block_size,
start,
})
}
fn skip_trailing_while_match<I, T>(it: &mut I, unwanted: &T) -> std::io::Result<Option<T>>
where
I: Iterator<Item = ::std::io::Result<T>>,
T: PartialEq,
{
loop {
match it.next() {
Some(Ok(ref t)) if t == unwanted => {},
Some(t) => return Ok(Some(t?)),
None => return Ok(None),
}
}
}
pub fn fill_buf_until_match<I, T>(it: &mut I, buf: &mut Vec<T>, want: T) -> std::io::Result<()>
where
I: Iterator<Item = std::io::Result<T>>,
T: PartialEq,
{
loop {
match it.next() {
Some(Ok(ref t)) if t == &want => return Ok(()),
Some(Ok(t)) => buf.push(t),
Some(Err(err)) => return Err(err),
None => return Ok(()),
}
}
}
pub fn fill_buf_to<I, T>(it: &mut I, buf: &mut Vec<T>, cap: usize) -> std::io::Result<()>
where
I: Iterator<Item = std::io::Result<T>>,
{
for _ in buf.len()..cap {
match it.next() {
Some(Ok(t)) => buf.push(t),
Some(Err(err)) => return Err(err),
None => break,
};
}
Ok(())
}