jq_rs/
errors.rs

1use std::error;
2use std::fmt;
3use std::result;
4
5const ERR_UNKNOWN: &str = "JQ: Unknown error";
6const ERR_COMPILE: &str = "JQ: Program failed to compile";
7const ERR_STRING_CONV: &str = "JQ: Failed to convert string";
8
9/// This is the common Result type for the crate. Fallible operations will
10/// return this.
11pub type Result<T> = result::Result<T, Error>;
12
13/// There are many potential causes for failure when running jq programs.
14/// This enum attempts to unify them all under a single type.
15#[derive(Debug)]
16pub enum Error {
17    /// The jq program failed to compile.
18    InvalidProgram,
19    /// System errors are raised by the internal jq state machine. These can
20    /// indicate problems parsing input, or even failures while initializing
21    /// the state machine itself.
22    System {
23        /// Feedback from jq about what went wrong, when available.
24        reason: Option<String>,
25    },
26    /// Errors encountered during conversion between CString/String or vice
27    /// versa.
28    StringConvert {
29        /// The original error which lead to this.
30        err: Box<dyn error::Error + 'static>,
31    },
32    /// Something bad happened, but it was unexpected.
33    Unknown,
34}
35
36unsafe impl Send for Error {}
37
38impl error::Error for Error {
39    fn description(&self) -> &str {
40        match self {
41            Error::StringConvert { .. } => ERR_STRING_CONV,
42            Error::InvalidProgram => ERR_COMPILE,
43            Error::System { reason } => reason
44                .as_ref()
45                .map(|x| x.as_str())
46                .unwrap_or_else(|| ERR_UNKNOWN),
47            Error::Unknown => ERR_UNKNOWN,
48        }
49    }
50
51    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
52        match self {
53            Error::StringConvert { err } => {
54                if let Some(err) = err.downcast_ref::<std::ffi::NulError>() {
55                    Some(err)
56                } else if let Some(err) = err.downcast_ref::<std::str::Utf8Error>() {
57                    Some(err)
58                } else {
59                    None
60                }
61            }
62            _ => None,
63        }
64    }
65}
66
67impl From<std::ffi::NulError> for Error {
68    fn from(err: std::ffi::NulError) -> Self {
69        Error::StringConvert { err: Box::new(err) }
70    }
71}
72
73impl From<std::str::Utf8Error> for Error {
74    fn from(err: std::str::Utf8Error) -> Self {
75        Error::StringConvert { err: Box::new(err) }
76    }
77}
78
79impl fmt::Display for Error {
80    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
81        let detail: String = match self {
82            Error::InvalidProgram => ERR_COMPILE.into(),
83            Error::System { reason } => reason
84                .as_ref()
85                .cloned()
86                .unwrap_or_else(|| ERR_UNKNOWN.into()),
87            Error::StringConvert { err } => format!("{} - `{}`", ERR_STRING_CONV, err),
88            Error::Unknown => ERR_UNKNOWN.into(),
89        };
90        write!(f, "{}", detail)
91    }
92}