dd-lib 0.2.1

library functions for a clone of the unix coreutil dd
Documentation
use opts;
use results::elapsed;
use std::{
    io::{Result, Write},
    time::SystemTime,
};
use units;

/// ErrHandler handles errors and progress information by writing to it's
/// internal writer.
pub struct ErrHandler<E: std::io::Write> {
    /// the internal writer (almost always [`Stderr`][std::io::StdErr])
    e: E,
    /// whether to make continual progress reports. See
    /// [opts::StatusLevel::Report]
    report: bool,
    /// Whether to continue on an io error. see [opts::Conv]
    continue_on_err: bool,

    /// when the previous report happened (in bytes, lines, or blcoks)
    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> {
    /// threshold of blocks written per report.
    pub const BLOCK_THRESHOLD_FOR_REPORT: usize = 25;
    /// threshold of lines written per report.
    pub const LINE_THRESHOLD_FOR_REPORT: usize = 20;
    /// threshold of bytes written per erport
    pub const STANDARD_BYTE_THRESHOLD: usize = 5 * units::MB;

    /// handle an error, promoting it unless `continue_on_error` is set.
    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)),
        }
    }

    /// report status during standard operation
    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() }
}