use core::fmt;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Position {
pub offset: u32,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct LineColumn {
pub line: u32,
pub column: u32,
}
impl Position {
pub const START: Self = Self { offset: 0 };
#[must_use]
pub const fn new(offset: u32) -> Self {
Self { offset }
}
#[must_use]
pub fn resolve(&self, input: &[u8]) -> LineColumn {
let upto = core::cmp::min(self.offset as usize, input.len());
let mut line: u32 = 1;
let mut last_newline: usize = 0;
let mut had_newline = false;
let mut i = 0;
while i < upto {
if input[i] == b'\n' {
line += 1;
last_newline = i + 1;
had_newline = true;
}
i += 1;
}
let col_start = if had_newline { last_newline } else { 0 };
let column = u32::try_from(upto - col_start + 1).unwrap_or(u32::MAX);
LineColumn { line, column }
}
}
impl fmt::Display for Position {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "byte {}", self.offset)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ErrorKind {
UnexpectedByte(u8),
UnexpectedEof,
InvalidEscape,
InvalidUnicodeEscape,
UnpairedSurrogate,
InvalidUtf8,
InvalidNumber,
NumberOutOfRange,
ControlCharInString,
TrailingData,
DepthLimitExceeded,
ExpectedValue,
ExpectedString,
ExpectedNumber,
ExpectedBool,
ExpectedNull,
ExpectedArray,
ExpectedObject,
TypeMismatch,
DuplicateKey,
MissingField,
UnknownField,
NonFiniteFloat,
}
impl ErrorKind {
#[must_use]
const fn lexical_msg(self) -> Option<&'static str> {
let msg = match self {
Self::UnexpectedByte(_) => "unexpected byte",
Self::UnexpectedEof => "unexpected end of input",
Self::InvalidEscape => "invalid string escape",
Self::InvalidUnicodeEscape => "invalid \\u escape",
Self::UnpairedSurrogate => "unpaired UTF-16 surrogate in \\u escape",
Self::InvalidUtf8 => "invalid UTF-8",
Self::InvalidNumber => "invalid number literal",
Self::NumberOutOfRange => "number does not fit target type",
Self::ControlCharInString => "control character in string literal",
Self::TrailingData => "trailing data after JSON value",
Self::DepthLimitExceeded => "nesting depth limit exceeded",
_ => return None,
};
Some(msg)
}
#[must_use]
const fn static_msg(self) -> &'static str {
if let Some(s) = self.lexical_msg() {
return s;
}
match self {
Self::ExpectedValue => "expected JSON value",
Self::ExpectedString => "expected string",
Self::ExpectedNumber => "expected number",
Self::ExpectedBool => "expected boolean",
Self::ExpectedNull => "expected null",
Self::ExpectedArray => "expected array",
Self::ExpectedObject => "expected object",
Self::TypeMismatch => "type mismatch",
Self::DuplicateKey => "duplicate object key",
Self::MissingField => "missing required field",
Self::UnknownField => "unknown field",
Self::NonFiniteFloat => "non-finite float not representable in JSON",
_ => "error",
}
}
}
impl fmt::Display for ErrorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Self::UnexpectedByte(b) = self {
return write!(f, "unexpected byte 0x{b:02x}");
}
f.write_str(self.static_msg())
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Error {
pub kind: ErrorKind,
pub position: Position,
}
impl Error {
#[must_use]
pub const fn new(kind: ErrorKind, position: Position) -> Self {
Self { kind, position }
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} at {}", self.kind, self.position)
}
}
#[cfg(feature = "std")]
impl std::error::Error for Error {}