use alloc::string::String;
use alloc::vec::Vec;
use core::fmt;
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum JsonLimitKind {
InputBytes,
Depth,
StringBytes,
KeyBytes,
NumberBytes,
ArrayItems,
ObjectMembers,
TotalNodes,
TotalDecodedStringBytes,
}
impl JsonLimitKind {
pub const fn as_str(self) -> &'static str {
match self {
Self::InputBytes => "input bytes",
Self::Depth => "nesting depth",
Self::StringBytes => "string bytes",
Self::KeyBytes => "key bytes",
Self::NumberBytes => "number bytes",
Self::ArrayItems => "array items",
Self::ObjectMembers => "object members",
Self::TotalNodes => "total nodes",
Self::TotalDecodedStringBytes => "total decoded string bytes",
}
}
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum JsonErrorKind {
UnexpectedEof,
UnexpectedByte,
InvalidUtf8,
InvalidEscape,
InvalidUnicodeEscape,
LoneSurrogate,
UnescapedControlCharacter,
InvalidNumber,
DuplicateKey,
TrailingData,
LimitExceeded(JsonLimitKind),
WriteFailure,
NonFiniteNumber,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum JsonPathSegment {
Key(String),
Index(usize),
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct JsonPath {
segments: Vec<JsonPathSegment>,
}
impl JsonPath {
pub(crate) fn from_segments(segments: Vec<JsonPathSegment>) -> Self {
Self { segments }
}
pub fn segments(&self) -> &[JsonPathSegment] {
&self.segments
}
}
impl fmt::Display for JsonPath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("$")?;
for segment in &self.segments {
match segment {
JsonPathSegment::Key(key) => write!(f, ".{key}")?,
JsonPathSegment::Index(index) => write!(f, "[{index}]")?,
}
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct JsonError {
kind: JsonErrorKind,
offset: usize,
line: usize,
column: usize,
path: Option<JsonPath>,
}
impl JsonError {
pub(crate) fn new(kind: JsonErrorKind, offset: usize, line: usize, column: usize) -> Self {
Self {
kind,
offset,
line,
column,
path: None,
}
}
pub(crate) fn with_path(mut self, path: JsonPath) -> Self {
self.path = Some(path);
self
}
#[cfg(feature = "canonical")]
pub(crate) fn serialization(kind: JsonErrorKind) -> Self {
Self {
kind,
offset: 0,
line: 0,
column: 0,
path: None,
}
}
pub fn kind(&self) -> &JsonErrorKind {
&self.kind
}
pub fn offset(&self) -> usize {
self.offset
}
pub fn line(&self) -> usize {
self.line
}
pub fn column(&self) -> usize {
self.column
}
pub fn path(&self) -> Option<&JsonPath> {
self.path.as_ref()
}
}
impl fmt::Display for JsonError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let message = match &self.kind {
JsonErrorKind::UnexpectedEof => "unexpected end of input",
JsonErrorKind::UnexpectedByte => "unexpected byte",
JsonErrorKind::InvalidUtf8 => "invalid UTF-8",
JsonErrorKind::InvalidEscape => "invalid escape sequence",
JsonErrorKind::InvalidUnicodeEscape => "invalid unicode escape",
JsonErrorKind::LoneSurrogate => "unpaired UTF-16 surrogate",
JsonErrorKind::UnescapedControlCharacter => "unescaped control character in string",
JsonErrorKind::InvalidNumber => "invalid number",
JsonErrorKind::DuplicateKey => "duplicate object key",
JsonErrorKind::TrailingData => "trailing data after JSON value",
JsonErrorKind::LimitExceeded(limit) => {
write!(
f,
"limit exceeded: {} at byte {}, line {}, column {}",
limit.as_str(),
self.offset,
self.line,
self.column
)?;
if let Some(path) = &self.path {
write!(f, ", path: {path}")?;
}
return Ok(());
}
JsonErrorKind::WriteFailure => return f.write_str("failed to write output"),
JsonErrorKind::NonFiniteNumber => {
return f.write_str("number is not representable as a finite f64");
}
};
write!(
f,
"{message} at byte {}, line {}, column {}",
self.offset, self.line, self.column
)?;
if let Some(path) = &self.path {
write!(f, ", path: {path}")?;
}
Ok(())
}
}
#[cfg(feature = "std")]
impl std::error::Error for JsonError {}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum JsonNumberError {
OutOfRange,
NotAnInteger,
NotFinite,
InvalidNumber,
}
impl fmt::Display for JsonNumberError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
Self::OutOfRange => "number out of range for target type",
Self::NotAnInteger => "number is not an integer",
Self::NotFinite => "number is not finite",
Self::InvalidNumber => "not a valid JSON number",
})
}
}
#[cfg(feature = "std")]
impl std::error::Error for JsonNumberError {}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum JsonDecodeErrorKind {
UnexpectedType,
MissingField,
Number,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct JsonDecodeError {
kind: JsonDecodeErrorKind,
message: &'static str,
}
impl JsonDecodeError {
pub const fn new(kind: JsonDecodeErrorKind, message: &'static str) -> Self {
Self { kind, message }
}
pub const fn kind(&self) -> JsonDecodeErrorKind {
self.kind
}
pub const fn message(&self) -> &'static str {
self.message
}
pub const fn unexpected_type(message: &'static str) -> Self {
Self::new(JsonDecodeErrorKind::UnexpectedType, message)
}
pub const fn missing_field(message: &'static str) -> Self {
Self::new(JsonDecodeErrorKind::MissingField, message)
}
pub const fn number(message: &'static str) -> Self {
Self::new(JsonDecodeErrorKind::Number, message)
}
}
impl fmt::Display for JsonDecodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.message)
}
}
#[cfg(feature = "std")]
impl std::error::Error for JsonDecodeError {}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum JsonFromStrError {
Parse(JsonError),
Decode(JsonDecodeError),
}
impl fmt::Display for JsonFromStrError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Parse(error) => write!(f, "invalid JSON: {error}"),
Self::Decode(error) => write!(f, "JSON did not match the target type: {error}"),
}
}
}
impl From<JsonError> for JsonFromStrError {
fn from(error: JsonError) -> Self {
Self::Parse(error)
}
}
impl From<JsonDecodeError> for JsonFromStrError {
fn from(error: JsonDecodeError) -> Self {
Self::Decode(error)
}
}
#[cfg(feature = "std")]
impl std::error::Error for JsonFromStrError {}