1use std::{fmt, io};
2
3use crate::parser::Token;
4
5pub type Result<T> = std::result::Result<T, Error>;
7
8#[derive(PartialEq)]
11pub struct Error {
12 inner: Box<ErrorImpl>,
13}
14
15#[derive(PartialEq)]
16struct ErrorImpl {
17 code: ErrorCode,
18 line: u32,
19 column: usize,
20 fragment: Option<String>,
21 token: Option<Token>,
22}
23
24#[derive(PartialEq)]
25pub(crate) enum ErrorCode {
26 Message(String),
28 ExpectedArray,
29 ExpectedArrayEnd,
30 ExpectedArraySeparator,
31 ExpectedBoolean,
32 ExpectedEnum,
33 ExpectedFloat,
34 ExpectedInteger,
35 ExpectedMap,
36 ExpectedMapEnd,
37 ExpectedMapEquals,
38 ExpectedMapSeparator,
39 ExpectedNull,
40 ExpectedString,
41 ExpectedTopLevelObject,
42 ExpectedValue,
43 TrailingCharacters,
44 NonFiniteFloat,
45}
46
47impl fmt::Display for ErrorCode {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 match self {
50 ErrorCode::Message(msg) => f.write_str(msg),
51 ErrorCode::ExpectedArray => f.write_str("expected an array value"),
52 ErrorCode::ExpectedArrayEnd => f.write_str("expected an array end delimiter"),
53 ErrorCode::ExpectedArraySeparator => {
54 f.write_str("expected comma or newline between array entries")
55 }
56 ErrorCode::ExpectedBoolean => f.write_str("expected a boolean value"),
57 ErrorCode::ExpectedEnum => f.write_str("expected string or object"),
58 ErrorCode::ExpectedFloat => f.write_str("expected floating point number"),
59 ErrorCode::ExpectedInteger => f.write_str("expected an integer value"),
60 ErrorCode::ExpectedMap => f.write_str("expected an object"),
61 ErrorCode::ExpectedMapEnd => f.write_str("expected an object end delimiter"),
62 ErrorCode::ExpectedMapEquals => f.write_str("expected a '=' between key and value"),
63 ErrorCode::ExpectedMapSeparator => {
64 f.write_str("expected comma or newline between object entries")
65 }
66 ErrorCode::ExpectedNull => f.write_str("expected null"),
67 ErrorCode::ExpectedString => f.write_str("expected a string value"),
68 ErrorCode::ExpectedTopLevelObject => f.write_str("expected object at the top level"),
69 ErrorCode::ExpectedValue => f.write_str("expected a value"),
70 ErrorCode::TrailingCharacters => f.write_str("unexpected trailing characters"),
71 ErrorCode::NonFiniteFloat => f.write_str("got infinite floating point number"),
72 }
73 }
74}
75
76impl fmt::Display for ErrorImpl {
77 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78 if self.line == 0 {
79 fmt::Display::fmt(&self.code, f)
80 } else {
81 write!(
82 f,
83 "{} at line {} column {}",
84 self.code, self.line, self.column
85 )
86 }
87 }
88}
89
90impl fmt::Display for Error {
91 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92 fmt::Display::fmt(&self.inner, f)
93 }
94}
95
96impl fmt::Debug for Error {
97 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98 write!(
99 f,
100 "Error({:?}, line: {}, column: {}, fragment: {:?}, token: {:?})",
101 self.inner.code.to_string(),
102 self.inner.line,
103 self.inner.column,
104 self.inner.fragment,
105 self.inner.token,
106 )
107 }
108}
109
110impl serde::de::Error for Error {
111 fn custom<T>(msg: T) -> Self
112 where
113 T: ToString,
114 {
115 let inner = Box::new(ErrorImpl {
116 code: ErrorCode::Message(msg.to_string()),
117 line: 0,
118 column: 0,
119 fragment: None,
120 token: None,
121 });
122 Self { inner }
123 }
124}
125
126impl serde::ser::Error for Error {
127 fn custom<T>(msg: T) -> Self
128 where
129 T: ToString,
130 {
131 let inner = Box::new(ErrorImpl {
132 code: ErrorCode::Message(msg.to_string()),
133 line: 0,
134 column: 0,
135 fragment: None,
136 token: None,
137 });
138 Self { inner }
139 }
140}
141
142impl std::error::Error for Error {}
143
144impl Error {
145 pub(crate) fn new(code: ErrorCode, line: u32, column: usize, fragment: Option<String>) -> Self {
146 Self {
147 inner: Box::new(ErrorImpl {
148 code,
149 line,
150 column,
151 fragment,
152 token: None,
153 }),
154 }
155 }
156 pub(crate) fn with_token(
157 code: ErrorCode,
158 line: u32,
159 column: usize,
160 fragment: Option<String>,
161 token: Token,
162 ) -> Self {
163 Self {
164 inner: Box::new(ErrorImpl {
165 code,
166 line,
167 column,
168 fragment,
169 token: Some(token),
170 }),
171 }
172 }
173}
174
175impl From<io::Error> for Error {
176 fn from(err: io::Error) -> Self {
177 Self::new(ErrorCode::Message(format!("{}", err)), 0, 0, None)
178 }
179}