argi/
error.rs

1//! Constructs for reporting errors within this library
2
3use crate::get_cur_exe;
4use std::{fmt, io};
5
6/// Crate-specific result type for ease-of-use
7pub type Result<T> = std::result::Result<T, Error>;
8
9/// Represents potential parsing errors which may occur
10#[derive(Debug)]
11pub enum Error {
12    /// Data was required after known command/argument in stack but was not found
13    DataRequired(Vec<String>),
14    /// Data was required for argument but was not found
15    DataRequiredArg(String), // FIXME: could add call here too
16    /// Input/output error
17    Io(io::Error),
18    /// Current executable name is invalid
19    InvalidCurExe,
20    /// Command name provided could not be found
21    CommandNotFound((String, Vec<String>)),
22    /// Argument name provided could not be found
23    ArgumentNotFound((String, Vec<String>)),
24    /// Nothing was inputted
25    NothingInputted,
26    /// Invalid data was provided
27    InvalidData(&'static str),
28}
29
30impl From<io::Error> for Error {
31    fn from(err: io::Error) -> Self {
32        Self::Io(err)
33    }
34}
35
36impl fmt::Display for Error {
37    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38        match self {
39            Error::DataRequired(call) => {
40                write!(
41                    f,
42                    "Data was required after \".. {}\" but was not found",
43                    fmt_call(call)
44                )
45            }
46            Error::DataRequiredArg(arg) => {
47                let fmt_arg = if arg.starts_with('-') {
48                    arg.clone()
49                } else if arg.len() == 1 {
50                    format!("-{}", arg)
51                } else {
52                    format!("--{}", arg)
53                };
54                write!(f, "Data was required for {} but was not found", fmt_arg)
55            }
56            Error::Io(err) => write!(f, "Input/output error, {}", err),
57            Error::InvalidCurExe => write!(f, "Current executable name is invalid"),
58            Error::CommandNotFound((cmd, call)) => {
59                write!(
60                    f,
61                    "Command `{}` not recognized, found inside of `{}` program call",
62                    cmd,
63                    fmt_call(call)
64                )
65            }
66            Error::ArgumentNotFound((arg, call)) => {
67                write!(
68                    f,
69                    "Argument {}{} not recognized, found inside of `{}` program call",
70                    arg_dashes(arg.len()),
71                    arg,
72                    fmt_call(call)
73                )
74            }
75            Error::NothingInputted => write!(f, "Nothing was inputted"),
76            Error::InvalidData(v) => write!(f, "Data provided could not be parsed to {}", v),
77        }
78    }
79}
80
81/// Formats dashes onto arguments, used instead of directly supplying original
82/// so `-abc` can be formatted down into `-b` potentially
83fn arg_dashes(arg_len: usize) -> &'static str {
84    if arg_len < 2 {
85        "-"
86    } else {
87        "--"
88    }
89}
90
91fn fmt_call(call: &[String]) -> String {
92    let left = match get_cur_exe() {
93        Ok(cur_exe) => cur_exe,
94        Err(_) => String::new(),
95    };
96    format!("{} {}", left, call.join(" "))
97}