Skip to main content

immutable_json/
error.rs

1use crate::api::Value;
2use crate::array::Array;
3#[cfg(feature = "jaq")]
4use jaq_core::compile::Errors;
5#[cfg(feature = "jaq")]
6use jaq_core::load::File;
7use std::fmt;
8use std::fmt::{Display, Formatter};
9use std::path::PathBuf;
10
11#[derive(Debug)]
12pub enum Error {
13    /// Cannot convert from another JSON representation to an immutable JSON value.
14    ConvertFrom,
15    /// Cannot convert from an immutable JSON value to another JSON representation.
16    ConvertTo,
17    #[cfg(feature = "jaq")]
18    /// A jaq compilation error. It requires the `jaq` crate feature.
19    JaqCompile(String),
20    #[cfg(feature = "jaq")]
21    /// An exception while running a jaq filter. It requires the `jaq` crate feature.
22    JaqException(String),
23    #[cfg(feature = "jaq")]
24    /// A jaq transformation didn't produce any result. It requires the `jaq` crate feature.
25    JaqNoResult,
26    /// Wrong array index.
27    JsonIndex(JsonIndexError),
28    #[cfg(feature = "patch")]
29    /// Invalid JSON patch.
30    JsonPatch(JsonPatchError),
31    /// Invalid JSON pointer.
32    JsonPointer(String),
33    /// A serde_json error.
34    SerdeJson(serde_json::Error),
35}
36
37impl Display for Error {
38    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
39        match self {
40            Error::ConvertFrom => write!(f, "cannot convert from serde_json or jaq_json"),
41            Error::ConvertTo => write!(f, "cannot convert to serde_json or jaq_json"),
42            #[cfg(feature = "jaq")]
43            Error::JaqCompile(s) => write!(f, "jaq compilation error: {}", s),
44            #[cfg(feature = "jaq")]
45            Error::JaqException(s) => write!(f, "jaq exception: {}", s),
46            #[cfg(feature = "jaq")]
47            Error::JaqNoResult => write!(f, "the jq expression did not yield a result"),
48            Error::JsonIndex(i) => write!(f, "{}", i),
49            Error::JsonPatch(p) => write!(f, "{}", p),
50            Error::JsonPointer(p) => write!(f, "malformed JSON pointer {}", p),
51            Error::SerdeJson(s) => write!(f, "{}", s),
52        }
53    }
54}
55
56impl std::error::Error for Error {}
57
58impl From<JsonIndexError> for Error {
59    fn from(value: JsonIndexError) -> Self {
60        Error::JsonIndex(value)
61    }
62}
63
64#[cfg(feature = "patch")]
65impl From<JsonPatchError> for Error {
66    fn from(value: JsonPatchError) -> Self {
67        Error::JsonPatch(value)
68    }
69}
70
71impl From<serde_json::Error> for Error {
72    fn from(value: serde_json::Error) -> Self {
73        Error::SerdeJson(value)
74    }
75}
76
77#[cfg(feature = "jaq")]
78impl From<Vec<(File<&str, PathBuf>, jaq_core::load::Error<&str>)>> for Error {
79    fn from(errors: Vec<(File<&str, PathBuf>, jaq_core::load::Error<&str>)>) -> Self {
80        Error::JaqCompile(
81            errors
82                .iter()
83                .map(|(file, error)| {
84                    pathbuf_to_string(file.path.clone())
85                        + ": code: "
86                        + file.code
87                        + ": error: "
88                        + &jaq_load_errors(error)
89                })
90                .fold(String::new(), |s, el| s + "\n" + &el),
91        )
92    }
93}
94
95#[cfg(feature = "jaq")]
96impl<'a> From<Errors<&'a str, PathBuf>> for Error {
97    fn from(errors: Errors<&'a str, PathBuf>) -> Self {
98        Error::JaqCompile(
99            errors
100                .iter()
101                .map(|(file, error)| {
102                    pathbuf_to_string(file.path.clone())
103                        + ": code: "
104                        + file.code
105                        + ":error: "
106                        + &jaq_compile_errors(error)
107                })
108                .fold(String::new(), |s, el| s + "\n" + &el),
109        )
110    }
111}
112
113/// Denotes a wrong JSON array index.
114#[derive(Debug, PartialEq)]
115pub struct JsonIndexError {
116    /// The index.
117    pub index: usize,
118    /// The length of the array.
119    pub len: usize,
120}
121
122impl Display for JsonIndexError {
123    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
124        write!(
125            f,
126            "the index {} is higher than {}",
127            self.index,
128            self.len - 1
129        )
130    }
131}
132
133#[derive(Debug)]
134#[cfg(feature = "patch")]
135pub struct JsonPatchError {
136    pub error: String,
137    pub patch: Box<Array>,
138    pub source: Box<Value>,
139}
140
141#[cfg(feature = "patch")]
142impl Display for JsonPatchError {
143    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
144        write!(
145            f,
146            "cannot apply path '{}' to source '{}' because of '{}",
147            self.patch, self.source, self.error
148        )
149    }
150}
151
152#[cfg(feature = "jaq")]
153fn jaq_compile_errors(errors: &Vec<jaq_core::compile::Error<&str>>) -> String {
154    errors
155        .iter()
156        .map(|(name, undefined)| undefined.as_str().to_string() + " " + name + " is undefined")
157        .fold(String::new(), |s, el| s + "\n" + &el)
158}
159
160#[cfg(feature = "jaq")]
161fn jaq_load_errors(error: &jaq_core::load::Error<&str>) -> String {
162    match error {
163        jaq_core::load::Error::Io(v) => v
164            .iter()
165            .map(|(p, e)| p.to_string() + ": " + e)
166            .fold(String::new(), |s, el| s + "\n" + &el),
167        jaq_core::load::Error::Lex(v) => jaq_read_error(v.iter().map(|(e, g)| (e.as_str(), *g))),
168        jaq_core::load::Error::Parse(v) => jaq_read_error(v.iter().map(|(e, g)| (e.as_str(), *g))),
169    }
170}
171
172#[cfg(feature = "jaq")]
173fn jaq_read_error<'a>(errors: impl Iterator<Item = (&'a str, &'a str)>) -> String {
174    errors
175        .map(|(e, g)| "expected ".to_string() + e + ", got " + g)
176        .fold(String::new(), |s, el| s + "\n" + &el)
177}
178
179#[cfg(feature = "jaq")]
180fn pathbuf_to_string(path_buf: PathBuf) -> String {
181    path_buf.into_os_string().to_str().unwrap_or("").to_string()
182}