1use core::fmt;
2
3#[derive(Copy, Clone, Debug, PartialEq, Eq)]
13pub struct Position {
14 pub offset: u32,
15}
16
17#[derive(Copy, Clone, Debug, PartialEq, Eq)]
21pub struct LineColumn {
22 pub line: u32,
23 pub column: u32,
24}
25
26impl Position {
27 pub const START: Self = Self { offset: 0 };
28
29 #[must_use]
30 pub const fn new(offset: u32) -> Self {
31 Self { offset }
32 }
33
34 #[must_use]
37 pub fn resolve(&self, input: &[u8]) -> LineColumn {
38 let upto = core::cmp::min(self.offset as usize, input.len());
39 let mut line: u32 = 1;
40 let mut last_newline: usize = 0;
41 let mut had_newline = false;
42 let mut i = 0;
43 while i < upto {
44 if input[i] == b'\n' {
45 line += 1;
46 last_newline = i + 1;
47 had_newline = true;
48 }
49 i += 1;
50 }
51 let col_start = if had_newline { last_newline } else { 0 };
52 let column = u32::try_from(upto - col_start + 1).unwrap_or(u32::MAX);
53 LineColumn { line, column }
54 }
55}
56
57impl fmt::Display for Position {
58 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59 write!(f, "byte {}", self.offset)
60 }
61}
62
63#[derive(Copy, Clone, Debug, PartialEq, Eq)]
64pub enum ErrorKind {
65 UnexpectedByte(u8),
66 UnexpectedEof,
67 InvalidEscape,
68 InvalidUnicodeEscape,
69 UnpairedSurrogate,
70 InvalidUtf8,
71 InvalidNumber,
72 NumberOutOfRange,
73 ControlCharInString,
74 TrailingData,
75 DepthLimitExceeded,
76 ExpectedValue,
77 ExpectedString,
78 ExpectedNumber,
79 ExpectedBool,
80 ExpectedNull,
81 ExpectedArray,
82 ExpectedObject,
83 TypeMismatch,
84 DuplicateKey,
85 MissingField,
86 UnknownField,
87 NonFiniteFloat,
88}
89
90impl ErrorKind {
91 #[must_use]
93 const fn lexical_msg(self) -> Option<&'static str> {
94 let msg = match self {
95 Self::UnexpectedByte(_) => "unexpected byte",
96 Self::UnexpectedEof => "unexpected end of input",
97 Self::InvalidEscape => "invalid string escape",
98 Self::InvalidUnicodeEscape => "invalid \\u escape",
99 Self::UnpairedSurrogate => "unpaired UTF-16 surrogate in \\u escape",
100 Self::InvalidUtf8 => "invalid UTF-8",
101 Self::InvalidNumber => "invalid number literal",
102 Self::NumberOutOfRange => "number does not fit target type",
103 Self::ControlCharInString => "control character in string literal",
104 Self::TrailingData => "trailing data after JSON value",
105 Self::DepthLimitExceeded => "nesting depth limit exceeded",
106 _ => return None,
107 };
108 Some(msg)
109 }
110
111 #[must_use]
114 const fn static_msg(self) -> &'static str {
115 if let Some(s) = self.lexical_msg() {
116 return s;
117 }
118 match self {
119 Self::ExpectedValue => "expected JSON value",
120 Self::ExpectedString => "expected string",
121 Self::ExpectedNumber => "expected number",
122 Self::ExpectedBool => "expected boolean",
123 Self::ExpectedNull => "expected null",
124 Self::ExpectedArray => "expected array",
125 Self::ExpectedObject => "expected object",
126 Self::TypeMismatch => "type mismatch",
127 Self::DuplicateKey => "duplicate object key",
128 Self::MissingField => "missing required field",
129 Self::UnknownField => "unknown field",
130 Self::NonFiniteFloat => "non-finite float not representable in JSON",
131 _ => "error",
132 }
133 }
134}
135
136impl fmt::Display for ErrorKind {
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 if let Self::UnexpectedByte(b) = self {
139 return write!(f, "unexpected byte 0x{b:02x}");
140 }
141 f.write_str(self.static_msg())
142 }
143}
144
145#[derive(Copy, Clone, Debug, PartialEq, Eq)]
146pub struct Error {
147 pub kind: ErrorKind,
148 pub position: Position,
149}
150
151impl Error {
152 #[must_use]
153 pub const fn new(kind: ErrorKind, position: Position) -> Self {
154 Self { kind, position }
155 }
156}
157
158impl fmt::Display for Error {
159 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
160 write!(f, "{} at {}", self.kind, self.position)
161 }
162}
163
164#[cfg(feature = "std")]
165impl std::error::Error for Error {}