1use std::{
14 fmt,
15 sync::Arc,
16};
17
18use crate::{
19 JsonDecodeErrorKind,
20 JsonDecodeStage,
21 JsonTopLevelKind,
22};
23
24#[non_exhaustive]
29#[derive(Debug, Clone)]
30pub struct JsonDecodeError {
31 pub kind: JsonDecodeErrorKind,
36 pub stage: JsonDecodeStage,
38 pub message: String,
43 pub expected_top_level: Option<JsonTopLevelKind>,
48 pub actual_top_level: Option<JsonTopLevelKind>,
53 pub line: Option<usize>,
58 pub column: Option<usize>,
63 pub input_bytes: Option<usize>,
65 pub max_input_bytes: Option<usize>,
67 source: Option<Arc<serde_json::Error>>,
69}
70
71impl JsonDecodeError {
72 #[inline]
75 pub(crate) fn input_too_large(actual_bytes: usize, max_bytes: usize) -> Self {
76 Self {
77 kind: JsonDecodeErrorKind::InputTooLarge,
78 stage: JsonDecodeStage::Normalize,
79 message: format!(
80 "JSON input is too large: {} bytes exceed configured limit {} bytes",
81 actual_bytes, max_bytes
82 ),
83 expected_top_level: None,
84 actual_top_level: None,
85 line: None,
86 column: None,
87 input_bytes: Some(actual_bytes),
88 max_input_bytes: Some(max_bytes),
89 source: None,
90 }
91 }
92
93 #[inline]
96 pub(crate) fn empty_input() -> Self {
97 Self {
98 kind: JsonDecodeErrorKind::EmptyInput,
99 stage: JsonDecodeStage::Normalize,
100 message: "JSON input is empty after normalization".to_string(),
101 expected_top_level: None,
102 actual_top_level: None,
103 line: None,
104 column: None,
105 input_bytes: None,
106 max_input_bytes: None,
107 source: None,
108 }
109 }
110
111 #[inline]
114 pub(crate) fn invalid_json(error: serde_json::Error, input_bytes: Option<usize>) -> Self {
115 let line = error.line();
116 let column = error.column();
117 let message = format!("Failed to parse JSON: {error}");
118 Self {
119 kind: JsonDecodeErrorKind::InvalidJson,
120 stage: JsonDecodeStage::Parse,
121 message,
122 expected_top_level: None,
123 actual_top_level: None,
124 line: (line > 0).then_some(line),
125 column: (column > 0).then_some(column),
126 input_bytes,
127 max_input_bytes: None,
128 source: Some(Arc::new(error)),
129 }
130 }
131
132 #[inline]
135 pub(crate) fn unexpected_top_level(
136 expected: JsonTopLevelKind,
137 actual: JsonTopLevelKind,
138 ) -> Self {
139 Self {
140 kind: JsonDecodeErrorKind::UnexpectedTopLevel,
141 stage: JsonDecodeStage::TopLevelCheck,
142 message: format!("Unexpected JSON top-level type: expected {expected}, got {actual}"),
143 expected_top_level: Some(expected),
144 actual_top_level: Some(actual),
145 line: None,
146 column: None,
147 input_bytes: None,
148 max_input_bytes: None,
149 source: None,
150 }
151 }
152
153 #[inline]
156 pub(crate) fn deserialize(error: serde_json::Error, input_bytes: Option<usize>) -> Self {
157 let line = error.line();
158 let column = error.column();
159 let message = format!("Failed to deserialize JSON value: {error}");
160 Self {
161 kind: JsonDecodeErrorKind::Deserialize,
162 stage: JsonDecodeStage::Deserialize,
163 message,
164 expected_top_level: None,
165 actual_top_level: None,
166 line: (line > 0).then_some(line),
167 column: (column > 0).then_some(column),
168 input_bytes,
169 max_input_bytes: None,
170 source: Some(Arc::new(error)),
171 }
172 }
173}
174
175impl PartialEq for JsonDecodeError {
176 fn eq(&self, other: &Self) -> bool {
177 self.kind == other.kind
178 && self.stage == other.stage
179 && self.message == other.message
180 && self.expected_top_level == other.expected_top_level
181 && self.actual_top_level == other.actual_top_level
182 && self.line == other.line
183 && self.column == other.column
184 && self.input_bytes == other.input_bytes
185 && self.max_input_bytes == other.max_input_bytes
186 }
187}
188
189impl Eq for JsonDecodeError {}
190
191impl fmt::Display for JsonDecodeError {
192 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
193 match self.kind {
194 JsonDecodeErrorKind::InputTooLarge => f.write_str(&self.message),
195 JsonDecodeErrorKind::EmptyInput => f.write_str(&self.message),
196 JsonDecodeErrorKind::UnexpectedTopLevel => f.write_str(&self.message),
197 JsonDecodeErrorKind::InvalidJson | JsonDecodeErrorKind::Deserialize => {
198 match (self.line, self.column) {
199 (Some(line), Some(column)) => {
200 write!(f, "{} (line {}, column {})", self.message, line, column)
201 }
202 _ => f.write_str(&self.message),
203 }
204 }
205 }
206 }
207}
208
209impl std::error::Error for JsonDecodeError {
210 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
211 self.source
212 .as_deref()
213 .map(|error| error as &(dyn std::error::Error + 'static))
214 }
215}