1use crate::libyaml::{emitter, error as libyaml};
2use crate::path::Path;
3use crate::{Marker, Span};
4use serde::{de, ser};
5use std::error::Error as StdError;
6use std::fmt::{self, Debug, Display};
7use std::io;
8use std::result;
9use std::string;
10use std::sync::Arc;
11
12pub struct Error(Box<ErrorImpl>);
14
15pub type Result<T> = result::Result<T, Error>;
17
18#[derive(Debug)]
19pub(crate) enum ErrorImpl {
20 Message(String, Option<Pos>),
21
22 Libyaml(libyaml::Error),
23 Io(io::Error),
24 FromUtf8(string::FromUtf8Error),
25
26 EndOfStream,
27 MoreThanOneDocument,
28 RecursionLimitExceeded(Marker),
29 RepetitionLimitExceeded,
30 BytesUnsupported,
31 UnknownAnchor(Marker),
32 DuplicateAnchor { first: Marker, second: Marker },
33 SerializeNestedEnum,
34 ScalarInMerge,
35 TaggedInMerge,
36 ScalarInMergeElement,
37 SequenceInMergeElement,
38 EmptyTag,
39 FailedToParseNumber,
40 FlattenNotMapping,
41
42 External(Box<dyn StdError + 'static + Send + Sync>),
43
44 Shared(Arc<ErrorImpl>),
45}
46
47#[derive(Debug)]
48pub(crate) struct Pos {
49 span: Span,
50 path: String,
51}
52
53impl Error {
54 pub fn location(&self) -> Option<Marker> {
72 self.0.location()
73 }
74
75 pub fn span(&self) -> Option<Span> {
79 self.0.span()
80 }
81
82 pub fn into_external(self) -> Option<Box<dyn StdError + 'static + Send + Sync>> {
85 if let ErrorImpl::External(err) = *self.0 {
86 Some(err)
87 } else {
88 None
89 }
90 }
91
92 pub fn is_duplicate_anchor(&self) -> bool {
94 self.0.is_duplicate_anchor()
95 }
96
97 pub fn display_no_mark(&self) -> impl Display + use<'_> {
99 struct MessageNoMark<'a>(&'a ErrorImpl);
100 impl Display for MessageNoMark<'_> {
101 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
102 match &self.0 {
103 ErrorImpl::Libyaml(err) => Display::fmt(err, f),
104 ErrorImpl::Shared(err) => err.display(f),
105 _ => self.0.message_no_mark(f),
106 }
107 }
108 }
109 MessageNoMark(&self.0)
110 }
111}
112
113pub(crate) fn new(inner: ErrorImpl) -> Error {
114 Error(Box::new(inner))
115}
116
117pub(crate) fn shared(shared: Arc<ErrorImpl>) -> Error {
118 Error(Box::new(ErrorImpl::Shared(shared)))
119}
120
121pub(crate) fn fix_mark(mut error: Error, mark: libyaml::Mark, path: Path) -> Error {
122 if let ErrorImpl::Message(_, none @ None) = error.0.as_mut() {
123 let span = Span::from(Marker::from(mark));
124
125 #[cfg(feature = "filename")]
126 let span = span.maybe_capture_filename();
127
128 *none = Some(Pos {
129 span,
130 path: path.to_string(),
131 });
132 }
133 error
134}
135
136pub(crate) fn set_span(mut error: Error, span: Span, path: Path) -> Error {
137 if let ErrorImpl::Message(_, pos) = error.0.as_mut() {
138 match pos {
139 Some(existing) => {
140 if !existing.span.is_valid() {
141 existing.span = span;
142 }
143 if existing.path == "." {
144 existing.path = path.to_string();
145 }
146 }
147 None => {
148 *pos = Some(Pos {
149 span,
150 path: path.to_string(),
151 });
152 }
153 }
154 }
155 error
156}
157
158impl Error {
159 pub(crate) fn shared(self) -> Arc<ErrorImpl> {
160 if let ErrorImpl::Shared(err) = *self.0 {
161 err
162 } else {
163 Arc::from(self.0)
164 }
165 }
166}
167
168impl From<libyaml::Error> for Error {
169 fn from(err: libyaml::Error) -> Self {
170 Error(Box::new(ErrorImpl::Libyaml(err)))
171 }
172}
173
174impl From<emitter::Error> for Error {
175 fn from(err: emitter::Error) -> Self {
176 match err {
177 emitter::Error::Libyaml(err) => Self::from(err),
178 emitter::Error::Io(err) => new(ErrorImpl::Io(err)),
179 }
180 }
181}
182
183impl From<Box<dyn StdError + 'static + Send + Sync>> for Error {
184 fn from(err: Box<dyn StdError + 'static + Send + Sync>) -> Self {
185 Error(Box::new(ErrorImpl::External(err)))
186 }
187}
188
189impl StdError for Error {
190 fn source(&self) -> Option<&(dyn StdError + 'static)> {
191 self.0.source()
192 }
193}
194
195impl Display for Error {
196 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
197 self.0.display(f)
198 }
199}
200
201impl Debug for Error {
204 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
205 self.0.debug(f)
206 }
207}
208
209impl ser::Error for Error {
210 fn custom<T: Display>(msg: T) -> Self {
211 Error(Box::new(ErrorImpl::Message(msg.to_string(), None)))
212 }
213}
214
215impl de::Error for Error {
216 fn custom<T: Display>(msg: T) -> Self {
217 Error(Box::new(ErrorImpl::Message(msg.to_string(), None)))
218 }
219}
220
221impl ErrorImpl {
222 fn is_duplicate_anchor(&self) -> bool {
223 match self {
224 ErrorImpl::DuplicateAnchor { .. } => true,
225 ErrorImpl::Shared(inner) => inner.is_duplicate_anchor(),
226 _ => false,
227 }
228 }
229
230 fn location(&self) -> Option<Marker> {
231 self.span().map(|span| span.start)
232 }
233
234 fn source(&self) -> Option<&(dyn StdError + 'static)> {
235 match self {
236 ErrorImpl::Io(err) => err.source(),
237 ErrorImpl::FromUtf8(err) => err.source(),
238 ErrorImpl::Shared(err) => err.source(),
239 ErrorImpl::External(err) => err.source(),
240 _ => None,
241 }
242 }
243
244 fn span(&self) -> Option<Span> {
245 match self {
246 ErrorImpl::Message(_, Some(Pos { span, path: _ })) => Some(span.clone()),
247 ErrorImpl::RecursionLimitExceeded(mark) | ErrorImpl::UnknownAnchor(mark) => {
248 Some(Span::from(*mark))
249 }
250 ErrorImpl::DuplicateAnchor { second, .. } => Some(Span::from(*second)),
251 ErrorImpl::Libyaml(err) => Some(Marker::from(err.mark()).into()),
252 ErrorImpl::Shared(err) => err.span(),
253 _ => None,
254 }
255 }
256
257 fn message_no_mark(&self, f: &mut fmt::Formatter) -> fmt::Result {
258 match self {
259 ErrorImpl::Message(msg, None) => f.write_str(msg),
260 ErrorImpl::Message(msg, Some(Pos { span: _, path })) => {
261 if path != "." {
262 write!(f, "{}: ", path)?;
263 }
264 f.write_str(msg)
265 }
266 ErrorImpl::Libyaml(_) => unreachable!(),
267 ErrorImpl::Io(err) => Display::fmt(err, f),
268 ErrorImpl::FromUtf8(err) => Display::fmt(err, f),
269 ErrorImpl::EndOfStream => f.write_str("EOF while parsing a value"),
270 ErrorImpl::MoreThanOneDocument => f.write_str(
271 "deserializing from YAML containing more than one document is not supported",
272 ),
273 ErrorImpl::RecursionLimitExceeded(_mark) => f.write_str("recursion limit exceeded"),
274 ErrorImpl::RepetitionLimitExceeded => f.write_str("repetition limit exceeded"),
275 ErrorImpl::BytesUnsupported => {
276 f.write_str("serialization and deserialization of bytes in YAML is not implemented")
277 }
278 ErrorImpl::UnknownAnchor(_mark) => f.write_str("unknown anchor"),
279 ErrorImpl::DuplicateAnchor { first, .. } => write!(
280 f,
281 "found duplicate anchor (first occurrence at line {} column {})",
282 first.line(),
283 first.column(),
284 ),
285 ErrorImpl::SerializeNestedEnum => {
286 f.write_str("serializing nested enums in YAML is not supported yet")
287 }
288 ErrorImpl::ScalarInMerge => {
289 f.write_str("expected a mapping or list of mappings for merging, but found scalar")
290 }
291 ErrorImpl::TaggedInMerge => f.write_str("unexpected tagged value in merge"),
292 ErrorImpl::ScalarInMergeElement => {
293 f.write_str("expected a mapping for merging, but found scalar")
294 }
295 ErrorImpl::SequenceInMergeElement => {
296 f.write_str("expected a mapping for merging, but found sequence")
297 }
298 ErrorImpl::EmptyTag => f.write_str("empty YAML tag is not allowed"),
299 ErrorImpl::FailedToParseNumber => f.write_str("failed to parse YAML number"),
300 ErrorImpl::External(err) => Display::fmt(err.as_ref(), f),
301 ErrorImpl::Shared(_) => unreachable!(),
302 ErrorImpl::FlattenNotMapping => write!(f, "expected the flatten field to be a mapping"),
303 }
304 }
305
306 fn display(&self, f: &mut fmt::Formatter) -> fmt::Result {
307 match self {
308 ErrorImpl::Libyaml(err) => Display::fmt(err, f),
309 ErrorImpl::Shared(err) => err.display(f),
310 _ => {
311 self.message_no_mark(f)?;
312 if let Some(mark) = self.location() {
313 if mark.line() != 0 || mark.column() != 0 {
314 write!(f, " at {}", mark)?;
315 }
316 }
317 Ok(())
318 }
319 }
320 }
321
322 fn debug(&self, f: &mut fmt::Formatter) -> fmt::Result {
323 match self {
324 ErrorImpl::Libyaml(err) => Debug::fmt(err, f),
325 ErrorImpl::Shared(err) => err.debug(f),
326 _ => {
327 f.write_str("Error(")?;
328 struct MessageNoMark<'a>(&'a ErrorImpl);
329 impl Display for MessageNoMark<'_> {
330 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
331 self.0.message_no_mark(f)
332 }
333 }
334 let msg = MessageNoMark(self).to_string();
335 Debug::fmt(&msg, f)?;
336 if let Some(mark) = self.location() {
337 write!(f, ", line: {}, column: {}", mark.line(), mark.column(),)?;
338 }
339 f.write_str(")")
340 }
341 }
342 }
343}