use std::{fmt, sync::Arc};
use crate::{JsonDecodeErrorKind, JsonDecodeStage, JsonTopLevelKind};
#[non_exhaustive]
#[derive(Debug, Clone)]
pub struct JsonDecodeError {
pub kind: JsonDecodeErrorKind,
pub stage: JsonDecodeStage,
pub message: String,
pub expected_top_level: Option<JsonTopLevelKind>,
pub actual_top_level: Option<JsonTopLevelKind>,
pub line: Option<usize>,
pub column: Option<usize>,
pub input_bytes: Option<usize>,
pub max_input_bytes: Option<usize>,
source: Option<Arc<serde_json::Error>>,
}
impl JsonDecodeError {
#[inline]
pub(crate) fn input_too_large(actual_bytes: usize, max_bytes: usize) -> Self {
Self {
kind: JsonDecodeErrorKind::InputTooLarge,
stage: JsonDecodeStage::Normalize,
message: format!(
"JSON input is too large: {} bytes exceed configured limit {} bytes",
actual_bytes, max_bytes
),
expected_top_level: None,
actual_top_level: None,
line: None,
column: None,
input_bytes: Some(actual_bytes),
max_input_bytes: Some(max_bytes),
source: None,
}
}
#[inline]
pub(crate) fn empty_input() -> Self {
Self {
kind: JsonDecodeErrorKind::EmptyInput,
stage: JsonDecodeStage::Normalize,
message: "JSON input is empty after normalization".to_string(),
expected_top_level: None,
actual_top_level: None,
line: None,
column: None,
input_bytes: None,
max_input_bytes: None,
source: None,
}
}
#[inline]
pub(crate) fn invalid_json(error: serde_json::Error, input_bytes: Option<usize>) -> Self {
let line = error.line();
let column = error.column();
let message = format!("Failed to parse JSON: {error}");
Self {
kind: JsonDecodeErrorKind::InvalidJson,
stage: JsonDecodeStage::Parse,
message,
expected_top_level: None,
actual_top_level: None,
line: (line > 0).then_some(line),
column: (column > 0).then_some(column),
input_bytes,
max_input_bytes: None,
source: Some(Arc::new(error)),
}
}
#[inline]
pub(crate) fn unexpected_top_level(
expected: JsonTopLevelKind,
actual: JsonTopLevelKind,
) -> Self {
Self {
kind: JsonDecodeErrorKind::UnexpectedTopLevel,
stage: JsonDecodeStage::TopLevelCheck,
message: format!("Unexpected JSON top-level type: expected {expected}, got {actual}"),
expected_top_level: Some(expected),
actual_top_level: Some(actual),
line: None,
column: None,
input_bytes: None,
max_input_bytes: None,
source: None,
}
}
#[inline]
pub(crate) fn deserialize(error: serde_json::Error, input_bytes: Option<usize>) -> Self {
let line = error.line();
let column = error.column();
let message = format!("Failed to deserialize JSON value: {error}");
Self {
kind: JsonDecodeErrorKind::Deserialize,
stage: JsonDecodeStage::Deserialize,
message,
expected_top_level: None,
actual_top_level: None,
line: (line > 0).then_some(line),
column: (column > 0).then_some(column),
input_bytes,
max_input_bytes: None,
source: Some(Arc::new(error)),
}
}
}
impl PartialEq for JsonDecodeError {
fn eq(&self, other: &Self) -> bool {
self.kind == other.kind
&& self.stage == other.stage
&& self.message == other.message
&& self.expected_top_level == other.expected_top_level
&& self.actual_top_level == other.actual_top_level
&& self.line == other.line
&& self.column == other.column
&& self.input_bytes == other.input_bytes
&& self.max_input_bytes == other.max_input_bytes
}
}
impl Eq for JsonDecodeError {}
impl fmt::Display for JsonDecodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.kind {
JsonDecodeErrorKind::InputTooLarge => f.write_str(&self.message),
JsonDecodeErrorKind::EmptyInput => f.write_str(&self.message),
JsonDecodeErrorKind::UnexpectedTopLevel => f.write_str(&self.message),
JsonDecodeErrorKind::InvalidJson | JsonDecodeErrorKind::Deserialize => {
match (self.line, self.column) {
(Some(line), Some(column)) => {
write!(f, "{} (line {}, column {})", self.message, line, column)
}
_ => f.write_str(&self.message),
}
}
}
}
}
impl std::error::Error for JsonDecodeError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.source
.as_deref()
.map(|error| error as &(dyn std::error::Error + 'static))
}
}