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
9pub type Result<T> = result::Result<T, Error>;
12
13#[derive(Debug)]
16pub enum Error {
17 InvalidProgram,
19 System {
23 reason: Option<String>,
25 },
26 StringConvert {
29 err: Box<dyn error::Error + 'static>,
31 },
32 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}