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