use opts;
use results::elapsed;
use std::{
io::{Result, Write},
time::SystemTime,
};
use units;
pub struct ErrHandler<E: std::io::Write> {
e: E,
report: bool,
continue_on_err: bool,
prev_report: usize,
}
impl<E: Write> ErrHandler<E> {
pub fn new(e: E, o: &opts::Opts) -> Self {
let report = o.status == opts::StatusLevel::Progress;
let continue_on_err = o.cflag(opts::CFlag::NOERROR);
ErrHandler {
e,
report,
continue_on_err,
prev_report: 0,
}
}
}
impl<E: Write> ErrHandler<E> {
pub const BLOCK_THRESHOLD_FOR_REPORT: usize = 25;
pub const LINE_THRESHOLD_FOR_REPORT: usize = 20;
pub const STANDARD_BYTE_THRESHOLD: usize = 5 * units::MB;
pub fn handle<T>(&mut self, res: Result<T>) -> Result<Option<T>> {
match (res, self.continue_on_err) {
(Err(err), true) => {
writeln!(self.e, "io error: <{}>; continuing", err);
Ok(None)
},
(Err(err), false) => Err(err),
(Ok(t), _) => Ok(Some(t)),
}
}
pub fn report_status_standard(&mut self, bytes: usize, start: &SystemTime) -> std::io::Result<()> {
if self.report && bytes.saturating_sub(self.prev_report) > Self::STANDARD_BYTE_THRESHOLD {
self.prev_report = bytes;
writeln!(
self,
"dd in progress: elapsed: {}: wrote {} bytes",
elapsed(start),
bytes
)?;
}
Ok(())
}
pub fn report_status_block(&mut self, lines: usize, start: &SystemTime) {
if self.report && lines % Self::LINE_THRESHOLD_FOR_REPORT == 0 {
writeln!(
self,
"dd in progress: unblock: elapsed: {}, wrote {} lines",
elapsed(&start),
lines
);
}
}
pub fn report_status_unblock(&mut self, blocks: usize, start: &SystemTime) {
if self.report && blocks % Self::BLOCK_THRESHOLD_FOR_REPORT == 0 {
writeln!(
self,
"dd in progress: unblock: elapsed: {}, wrote {} fixed-length blocks",
elapsed(&start),
blocks
);
}
}
}
impl<E: Write> Write for ErrHandler<E> {
fn write(&mut self, buf: &[u8]) -> Result<usize> { self.e.write(buf) }
fn flush(&mut self) -> Result<()> { self.e.flush() }
}