1 use crate::libyaml::{emitter, error as libyaml};
2 use crate::path::Path;
3 use serde::{de, ser};
4 use std::error::Error as StdError;
5 use std::fmt::{self, Debug, Display};
6 use std::io;
7 use std::result;
8 use std::string;
9 use std::sync::Arc;
10
11 /// An error that happened serializing or deserializing YAML data.
12 pub struct Error(Box<ErrorImpl>);
13
14 /// Alias for a `Result` with the error type `serde_yaml::Error`.
15 pub type Result<T> = result::Result<T, Error>;
16
17 #[derive(Debug)]
18 pub(crate) enum ErrorImpl {
19 Message(String, Option<Pos>),
20
21 Libyaml(libyaml::Error),
22 Io(io::Error),
23 FromUtf8(string::FromUtf8Error),
24
25 EndOfStream,
26 MoreThanOneDocument,
27 RecursionLimitExceeded(libyaml::Mark),
28 RepetitionLimitExceeded,
29 BytesUnsupported,
30 UnknownAnchor(libyaml::Mark),
31 SerializeNestedEnum,
32 ScalarInMerge,
33 TaggedInMerge,
34 ScalarInMergeElement,
35 SequenceInMergeElement,
36 EmptyTag,
37 FailedToParseNumber,
38
39 Shared(Arc<ErrorImpl>),
40 }
41
42 #[derive(Debug)]
43 pub(crate) struct Pos {
44 mark: libyaml::Mark,
45 path: String,
46 }
47
48 /// The input location that an error occured.
49 #[derive(Debug)]
50 pub struct Location {
51 index: usize,
52 line: usize,
53 column: usize,
54 }
55
56 impl Location {
57 /// The byte index of the error
index(&self) -> usize58 pub fn index(&self) -> usize {
59 self.index
60 }
61
62 /// The line of the error
line(&self) -> usize63 pub fn line(&self) -> usize {
64 self.line
65 }
66
67 /// The column of the error
column(&self) -> usize68 pub fn column(&self) -> usize {
69 self.column
70 }
71
72 // This is to keep decoupled with the yaml crate
73 #[doc(hidden)]
from_mark(mark: libyaml::Mark) -> Self74 fn from_mark(mark: libyaml::Mark) -> Self {
75 Location {
76 index: mark.index() as usize,
77 // `line` and `column` returned from libyaml are 0-indexed but all error messages add +1 to this value
78 line: mark.line() as usize + 1,
79 column: mark.column() as usize + 1,
80 }
81 }
82 }
83
84 impl Error {
85 /// Returns the Location from the error if one exists.
86 ///
87 /// Not all types of errors have a location so this can return `None`.
88 ///
89 /// # Examples
90 ///
91 /// ```
92 /// # use serde_yaml::{Value, Error};
93 /// #
94 /// // The `@` character as the first character makes this invalid yaml
95 /// let invalid_yaml: Result<Value, Error> = serde_yaml::from_str("@invalid_yaml");
96 ///
97 /// let location = invalid_yaml.unwrap_err().location().unwrap();
98 ///
99 /// assert_eq!(location.line(), 1);
100 /// assert_eq!(location.column(), 1);
101 /// ```
location(&self) -> Option<Location>102 pub fn location(&self) -> Option<Location> {
103 self.0.location()
104 }
105 }
106
new(inner: ErrorImpl) -> Error107 pub(crate) fn new(inner: ErrorImpl) -> Error {
108 Error(Box::new(inner))
109 }
110
shared(shared: Arc<ErrorImpl>) -> Error111 pub(crate) fn shared(shared: Arc<ErrorImpl>) -> Error {
112 Error(Box::new(ErrorImpl::Shared(shared)))
113 }
114
fix_mark(mut error: Error, mark: libyaml::Mark, path: Path) -> Error115 pub(crate) fn fix_mark(mut error: Error, mark: libyaml::Mark, path: Path) -> Error {
116 if let ErrorImpl::Message(_, none @ None) = error.0.as_mut() {
117 *none = Some(Pos {
118 mark,
119 path: path.to_string(),
120 });
121 }
122 error
123 }
124
125 impl Error {
shared(self) -> Arc<ErrorImpl>126 pub(crate) fn shared(self) -> Arc<ErrorImpl> {
127 if let ErrorImpl::Shared(err) = *self.0 {
128 err
129 } else {
130 Arc::from(self.0)
131 }
132 }
133 }
134
135 impl From<libyaml::Error> for Error {
from(err: libyaml::Error) -> Self136 fn from(err: libyaml::Error) -> Self {
137 Error(Box::new(ErrorImpl::Libyaml(err)))
138 }
139 }
140
141 impl From<emitter::Error> for Error {
from(err: emitter::Error) -> Self142 fn from(err: emitter::Error) -> Self {
143 match err {
144 emitter::Error::Libyaml(err) => Self::from(err),
145 emitter::Error::Io(err) => new(ErrorImpl::Io(err)),
146 }
147 }
148 }
149
150 impl StdError for Error {
source(&self) -> Option<&(dyn StdError + 'static)>151 fn source(&self) -> Option<&(dyn StdError + 'static)> {
152 self.0.source()
153 }
154 }
155
156 impl Display for Error {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result157 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
158 self.0.display(f)
159 }
160 }
161
162 // Remove two layers of verbosity from the debug representation. Humans often
163 // end up seeing this representation because it is what unwrap() shows.
164 impl Debug for Error {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result165 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
166 self.0.debug(f)
167 }
168 }
169
170 impl ser::Error for Error {
custom<T: Display>(msg: T) -> Self171 fn custom<T: Display>(msg: T) -> Self {
172 Error(Box::new(ErrorImpl::Message(msg.to_string(), None)))
173 }
174 }
175
176 impl de::Error for Error {
custom<T: Display>(msg: T) -> Self177 fn custom<T: Display>(msg: T) -> Self {
178 Error(Box::new(ErrorImpl::Message(msg.to_string(), None)))
179 }
180 }
181
182 impl ErrorImpl {
location(&self) -> Option<Location>183 fn location(&self) -> Option<Location> {
184 self.mark().map(Location::from_mark)
185 }
186
source(&self) -> Option<&(dyn StdError + 'static)>187 fn source(&self) -> Option<&(dyn StdError + 'static)> {
188 match self {
189 ErrorImpl::Io(err) => err.source(),
190 ErrorImpl::FromUtf8(err) => err.source(),
191 ErrorImpl::Shared(err) => err.source(),
192 _ => None,
193 }
194 }
195
mark(&self) -> Option<libyaml::Mark>196 fn mark(&self) -> Option<libyaml::Mark> {
197 match self {
198 ErrorImpl::Message(_, Some(Pos { mark, path: _ }))
199 | ErrorImpl::RecursionLimitExceeded(mark)
200 | ErrorImpl::UnknownAnchor(mark) => Some(*mark),
201 ErrorImpl::Libyaml(err) => Some(err.mark()),
202 ErrorImpl::Shared(err) => err.mark(),
203 _ => None,
204 }
205 }
206
message_no_mark(&self, f: &mut fmt::Formatter) -> fmt::Result207 fn message_no_mark(&self, f: &mut fmt::Formatter) -> fmt::Result {
208 match self {
209 ErrorImpl::Message(msg, None) => f.write_str(msg),
210 ErrorImpl::Message(msg, Some(Pos { mark: _, path })) => {
211 if path != "." {
212 write!(f, "{}: ", path)?;
213 }
214 f.write_str(msg)
215 }
216 ErrorImpl::Libyaml(_) => unreachable!(),
217 ErrorImpl::Io(err) => Display::fmt(err, f),
218 ErrorImpl::FromUtf8(err) => Display::fmt(err, f),
219 ErrorImpl::EndOfStream => f.write_str("EOF while parsing a value"),
220 ErrorImpl::MoreThanOneDocument => f.write_str(
221 "deserializing from YAML containing more than one document is not supported",
222 ),
223 ErrorImpl::RecursionLimitExceeded(_mark) => f.write_str("recursion limit exceeded"),
224 ErrorImpl::RepetitionLimitExceeded => f.write_str("repetition limit exceeded"),
225 ErrorImpl::BytesUnsupported => {
226 f.write_str("serialization and deserialization of bytes in YAML is not implemented")
227 }
228 ErrorImpl::UnknownAnchor(_mark) => f.write_str("unknown anchor"),
229 ErrorImpl::SerializeNestedEnum => {
230 f.write_str("serializing nested enums in YAML is not supported yet")
231 }
232 ErrorImpl::ScalarInMerge => {
233 f.write_str("expected a mapping or list of mappings for merging, but found scalar")
234 }
235 ErrorImpl::TaggedInMerge => f.write_str("unexpected tagged value in merge"),
236 ErrorImpl::ScalarInMergeElement => {
237 f.write_str("expected a mapping for merging, but found scalar")
238 }
239 ErrorImpl::SequenceInMergeElement => {
240 f.write_str("expected a mapping for merging, but found sequence")
241 }
242 ErrorImpl::EmptyTag => f.write_str("empty YAML tag is not allowed"),
243 ErrorImpl::FailedToParseNumber => f.write_str("failed to parse YAML number"),
244 ErrorImpl::Shared(_) => unreachable!(),
245 }
246 }
247
display(&self, f: &mut fmt::Formatter) -> fmt::Result248 fn display(&self, f: &mut fmt::Formatter) -> fmt::Result {
249 match self {
250 ErrorImpl::Libyaml(err) => Display::fmt(err, f),
251 ErrorImpl::Shared(err) => err.display(f),
252 _ => {
253 self.message_no_mark(f)?;
254 if let Some(mark) = self.mark() {
255 if mark.line() != 0 || mark.column() != 0 {
256 write!(f, " at {}", mark)?;
257 }
258 }
259 Ok(())
260 }
261 }
262 }
263
debug(&self, f: &mut fmt::Formatter) -> fmt::Result264 fn debug(&self, f: &mut fmt::Formatter) -> fmt::Result {
265 match self {
266 ErrorImpl::Libyaml(err) => Debug::fmt(err, f),
267 ErrorImpl::Shared(err) => err.debug(f),
268 _ => {
269 f.write_str("Error(")?;
270 struct MessageNoMark<'a>(&'a ErrorImpl);
271 impl<'a> Display for MessageNoMark<'a> {
272 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
273 self.0.message_no_mark(f)
274 }
275 }
276 let msg = MessageNoMark(self).to_string();
277 Debug::fmt(&msg, f)?;
278 if let Some(mark) = self.mark() {
279 write!(
280 f,
281 ", line: {}, column: {}",
282 mark.line() + 1,
283 mark.column() + 1,
284 )?;
285 }
286 f.write_str(")")
287 }
288 }
289 }
290 }
291