1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
//! Structs, enums, and error types for reporting success and failure.
use opts;
use std::{borrow::Cow, fmt, time::SystemTime};
#[derive(Debug, PartialEq, Eq, Clone)]
/// A successful output from [`dd`][super::dd]
pub enum Success {
    /// Normal operation reports the number of bytes copied.
    /// Corresponds to [`opts::Mode::Standard`]
    Bytes {
        /// bytes successfuly written
        bytes: usize,
        /// start time of operation
        start: SystemTime,
    },
    /// Unblock reports the number of fixed-sized records copied and the block
    /// size. Corresponds to [`opts::Mode::Unblock`]
    Unblock {
        /// number of blocks successfully written
        blocks: usize,
        /// block size (in bytes) of fixed-sized records
        block_size: usize,
        start: SystemTime,
    },
    /// [`opts::Mode::Block`]
    Block {
        /// number of newline or EOF-terminated lines
        lines: usize,
        /// lines truncated to `block_size`
        truncated: usize,
        /// lines padded with spaces to block_size
        padded: usize,
        /// block_size (in bytes)
        block_size: usize,
        /// system time at start of operation
        start: SystemTime,
    },
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]
/// An Error in operation of [`dd`][super::dd]
pub enum Error {
    /// An error while reading, writing, or converting. See [io][super::io].
    IO(std::io::Error),
    /// An user input error corresponding to an incorectly specified,
    /// unimplemented, or conflicting option.
    Opt(opts::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::IO(err) => write!(f, "io error: {}", err),
            Error::Opt(err) => write!(f, "command line argument error: {}", err),
        }
    }
}

impl From<std::io::Error> for Error {
    fn from(err: ::std::io::Error) -> Self { Error::IO(err) }
}
impl From<opts::Error> for Error {
    fn from(err: opts::Error) -> Self { Error::Opt(err) }
}
impl std::error::Error for Error {}
impl fmt::Display for Success {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Success::Bytes { bytes, start } => write!(f, "wrote {} bytes in {}", bytes, elapsed(start)),
            Success::Block {
                lines,
                truncated,
                padded,
                block_size,
                start,
            } => write!(
                f,
                concat!(
                    "Wrote {lines} lines of length {len} in {seconds}.\n",
                    "Padded {padded}/{len} lines\n",
                    "Truncated {truncated}/{len} lines\n"
                ),
                lines = lines,
                truncated = truncated,
                len = block_size,
                padded = padded,
                seconds = elapsed(start),
            ),
            Success::Unblock {
                blocks,
                block_size,
                start,
            } => write!(
                f,
                "wrote {} records of fixed size {} in {}",
                blocks,
                block_size,
                elapsed(start)
            ),
        }
    }
}

//// the elapsed time in seconds, with three decimal digits of precision
pub fn elapsed(start: &SystemTime) -> Cow<'static, str> {
    match start.elapsed() {
        Ok(elapsed) => Cow::Owned(format!("{}.{:03} seconds", elapsed.as_secs(), elapsed.subsec_millis())),
        _ => Cow::Borrowed("<error obtaining elapsed time>"),
    }
}