1use crate::json_parser;
2
3#[derive(Debug)]
11#[non_exhaustive]
12pub enum JsonToolsError {
13 JsonParseError {
15 message: String,
16 suggestion: String,
17 source: json_parser::JsonError,
18 },
19
20 RegexError {
22 message: String,
23 suggestion: String,
24 source: regex::Error,
25 },
26
27 InvalidReplacementPattern { message: String, suggestion: String },
29
30 InvalidJsonStructure { message: String, suggestion: String },
32
33 ConfigurationError { message: String, suggestion: String },
35
36 BatchProcessingError {
38 index: usize,
39 message: String,
40 suggestion: String,
41 source: Box<JsonToolsError>,
42 },
43
44 InputValidationError { message: String, suggestion: String },
46
47 SerializationError {
49 message: String,
50 suggestion: String,
51 source: json_parser::JsonError,
52 },
53}
54
55impl std::fmt::Display for JsonToolsError {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 match self {
58 Self::JsonParseError {
59 message,
60 suggestion,
61 ..
62 } => {
63 write!(
64 f,
65 "[E001] JSON parsing failed: {message}\n\u{1f4a1} Suggestion: {suggestion}"
66 )
67 }
68 Self::RegexError {
69 message,
70 suggestion,
71 ..
72 } => {
73 write!(
74 f,
75 "[E002] Regex pattern error: {message}\n\u{1f4a1} Suggestion: {suggestion}"
76 )
77 }
78 Self::InvalidReplacementPattern {
79 message,
80 suggestion,
81 } => {
82 write!(f, "[E003] Invalid replacement pattern: {message}\n\u{1f4a1} Suggestion: {suggestion}")
83 }
84 Self::InvalidJsonStructure {
85 message,
86 suggestion,
87 } => {
88 write!(
89 f,
90 "[E004] Invalid JSON structure: {message}\n\u{1f4a1} Suggestion: {suggestion}"
91 )
92 }
93 Self::ConfigurationError {
94 message,
95 suggestion,
96 } => {
97 write!(f, "[E005] Operation mode not configured: {message}\n\u{1f4a1} Suggestion: {suggestion}")
98 }
99 Self::BatchProcessingError {
100 index,
101 message,
102 suggestion,
103 ..
104 } => {
105 write!(f, "[E006] Batch processing failed at index {index}: {message}\n\u{1f4a1} Suggestion: {suggestion}")
106 }
107 Self::InputValidationError {
108 message,
109 suggestion,
110 } => {
111 write!(
112 f,
113 "[E007] Input validation failed: {message}\n\u{1f4a1} Suggestion: {suggestion}"
114 )
115 }
116 Self::SerializationError {
117 message,
118 suggestion,
119 ..
120 } => {
121 write!(f, "[E008] JSON serialization failed: {message}\n\u{1f4a1} Suggestion: {suggestion}")
122 }
123 }
124 }
125}
126
127impl std::error::Error for JsonToolsError {
128 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
129 match self {
130 Self::JsonParseError { source, .. } => Some(source),
131 Self::RegexError { source, .. } => Some(source),
132 Self::BatchProcessingError { source, .. } => Some(source.as_ref()),
133 Self::SerializationError { source, .. } => Some(source),
134 _ => None,
135 }
136 }
137}
138
139impl JsonToolsError {
140 pub fn error_code(&self) -> &'static str {
156 match self {
157 JsonToolsError::JsonParseError { .. } => "E001",
158 JsonToolsError::RegexError { .. } => "E002",
159 JsonToolsError::InvalidReplacementPattern { .. } => "E003",
160 JsonToolsError::InvalidJsonStructure { .. } => "E004",
161 JsonToolsError::ConfigurationError { .. } => "E005",
162 JsonToolsError::BatchProcessingError { .. } => "E006",
163 JsonToolsError::InputValidationError { .. } => "E007",
164 JsonToolsError::SerializationError { .. } => "E008",
165 }
166 }
167
168 #[cold] #[inline(never)]
171 pub fn json_parse_error(source: json_parser::JsonError) -> Self {
172 let suggestion = "Verify your JSON syntax using a JSON validator. Common issues include: missing quotes around keys or values, trailing commas, unescaped characters, incomplete JSON (missing closing braces or brackets), or invalid escape sequences.";
173
174 JsonToolsError::JsonParseError {
175 message: source.to_string(),
176 suggestion: suggestion.into(),
177 source,
178 }
179 }
180
181 #[cold] #[inline(never)]
184 pub fn regex_error(source: regex::Error) -> Self {
185 let suggestion = match source {
186 regex::Error::Syntax(_) =>
187 "Check your regex pattern syntax. Use online regex testers to validate your pattern. Remember to escape special characters like '.', '*', '+', '?', etc.",
188 regex::Error::CompiledTooBig(_) =>
189 "Your regex pattern is too complex. Try simplifying it or breaking it into multiple smaller patterns.",
190 _ => "Verify your regex pattern is valid. Use tools like regex101.com to test and debug your pattern.",
191 };
192
193 JsonToolsError::RegexError {
194 message: source.to_string(),
195 suggestion: suggestion.into(),
196 source,
197 }
198 }
199
200 #[cold] #[inline(never)]
203 pub fn invalid_replacement_pattern(message: impl Into<String>) -> Self {
204 let msg = message.into();
205 let suggestion = if msg.contains("pairs") {
206 "Replacement patterns must be provided in pairs (pattern, replacement). Ensure you have an even number of arguments."
207 } else if msg.contains("regex") {
208 "Patterns are matched literally (exact substring) by default. Wrap a pattern in r'...' to use it as a regex instead, e.g. r'^user_' to match keys starting with 'user_'."
209 } else {
210 "Check your replacement pattern configuration. Patterns should be in the format: pattern1, replacement1, pattern2, replacement2, etc."
211 };
212
213 JsonToolsError::InvalidReplacementPattern {
214 message: msg,
215 suggestion: suggestion.into(),
216 }
217 }
218
219 #[cold] #[inline(never)]
222 pub fn invalid_json_structure(message: impl Into<String>) -> Self {
223 let msg = message.into();
224 let suggestion = if msg.contains("unflatten") {
225 "For unflattening, ensure your JSON is a flat object with dot-separated keys like {'user.name': 'John', 'user.age': 30}."
226 } else if msg.contains("object") {
227 "The operation requires a JSON object ({}), but received a different type. Check that your input is a valid JSON object."
228 } else {
229 "Verify that your JSON structure is compatible with the requested operation. Flattening works on nested objects/arrays, unflattening works on flat objects."
230 };
231
232 JsonToolsError::InvalidJsonStructure {
233 message: msg,
234 suggestion: suggestion.into(),
235 }
236 }
237
238 #[cold] #[inline(never)]
241 pub fn configuration_error(message: impl Into<String>) -> Self {
242 JsonToolsError::ConfigurationError {
243 message: message.into(),
244 suggestion: "Call .flatten() or .unflatten() on your JSONTools instance before calling .execute() to set the operation mode.".into(),
245 }
246 }
247
248 #[cold] #[inline(never)]
251 pub fn batch_processing_error(index: usize, source: JsonToolsError) -> Self {
252 JsonToolsError::BatchProcessingError {
253 index,
254 message: format!("Failed to process item at index {}", index),
255 suggestion: "Check the JSON at the specified index. All items in a batch must be valid JSON strings or objects.".to_string(),
256 source: Box::new(source),
257 }
258 }
259
260 #[cold] #[inline(never)]
263 pub fn input_validation_error(message: impl Into<String>) -> Self {
264 let msg = message.into();
265 let suggestion = if msg.contains("type") {
266 "Ensure your input is a valid JSON string, Python dict, or list of JSON strings/dicts."
267 } else if msg.contains("empty") {
268 "Provide non-empty input for processing."
269 } else {
270 "Check that your input format matches the expected type for the operation."
271 };
272
273 JsonToolsError::InputValidationError {
274 message: msg,
275 suggestion: suggestion.to_string(),
276 }
277 }
278
279 #[cold] #[inline(never)]
282 pub fn serialization_error(source: json_parser::JsonError) -> Self {
283 JsonToolsError::SerializationError {
284 message: source.to_string(),
285 suggestion: "This is likely an internal error. The processed data couldn't be serialized back to JSON. Please report this issue.".to_string(),
286 source,
287 }
288 }
289}
290
291impl From<json_parser::JsonError> for JsonToolsError {
293 fn from(error: json_parser::JsonError) -> Self {
294 JsonToolsError::json_parse_error(error)
295 }
296}
297
298impl From<regex::Error> for JsonToolsError {
300 fn from(error: regex::Error) -> Self {
301 JsonToolsError::regex_error(error)
302 }
303}
304
305#[cfg(feature = "python")]
307impl From<pyo3::PyErr> for JsonToolsError {
308 fn from(err: pyo3::PyErr) -> Self {
309 JsonToolsError::configuration_error(format!("Python error: {err}"))
310 }
311}
312
313#[cfg(feature = "jvm")]
315impl From<jni::errors::Error> for JsonToolsError {
316 fn from(err: jni::errors::Error) -> Self {
317 JsonToolsError::configuration_error(format!("JNI error: {err}"))
318 }
319}