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