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 ConvertFrom,
15 ConvertTo,
17 #[cfg(feature = "jaq")]
18 JaqCompile(String),
20 #[cfg(feature = "jaq")]
21 JaqException(String),
23 #[cfg(feature = "jaq")]
24 JaqNoResult,
26 JsonIndex(JsonIndexError),
28 #[cfg(feature = "patch")]
29 JsonPatch(JsonPatchError),
31 JsonPointer(String),
33 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#[derive(Debug, PartialEq)]
115pub struct JsonIndexError {
116 pub index: usize,
118 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}