1use crate::libyaml::{
2 emitter,
3 error as libyaml,
4};
5use crate::path::Path;
6use serde::{
7 de,
8 ser,
9};
10use std::error::Error as StdError;
11use std::fmt::{
12 self,
13 Debug,
14 Display,
15};
16use std::sync::Arc;
17use std::{
18 io,
19 result,
20 string,
21};
22
23pub struct Error(Box<ErrorImpl>);
25
26pub type Result<T> = result::Result<T, Error>;
28
29#[derive(Debug)]
30pub(crate) enum ErrorImpl {
31 Message(String, Option<Pos>),
32
33 Libyaml(libyaml::Error),
34 Io(io::Error),
35 FromUtf8(string::FromUtf8Error),
36
37 EndOfStream,
38 MoreThanOneDocument,
39 RecursionLimitExceeded(libyaml::Mark),
40 RepetitionLimitExceeded,
41 BytesUnsupported,
42 UnknownAnchor(libyaml::Mark),
43 SerializeNestedEnum,
44 ScalarInMerge,
45 TaggedInMerge,
46 ScalarInMergeElement,
47 SequenceInMergeElement,
48 EmptyTag,
49 FailedToParseNumber,
50
51 Shared(Arc<ErrorImpl>),
52}
53
54#[derive(Debug)]
55pub(crate) struct Pos {
56 mark: libyaml::Mark,
57 path: String,
58}
59
60#[derive(Debug)]
62pub struct Location {
63 index: usize,
64 line: usize,
65 column: usize,
66}
67
68impl Location {
69 pub fn index(&self) -> usize {
71 self.index
72 }
73
74 pub fn line(&self) -> usize {
76 self.line
77 }
78
79 pub fn column(&self) -> usize {
81 self.column
82 }
83
84 #[doc(hidden)]
86 fn from_mark(mark: libyaml::Mark) -> Self {
87 Location {
88 index: mark.index() as usize,
89 line: mark.line() as usize + 1,
91 column: mark.column() as usize + 1,
92 }
93 }
94}
95
96impl Error {
97 pub fn location(&self) -> Option<Location> {
115 self.0.location()
116 }
117}
118
119pub(crate) fn new(inner: ErrorImpl) -> Error {
120 Error(Box::new(inner))
121}
122
123pub(crate) fn shared(shared: Arc<ErrorImpl>) -> Error {
124 Error(Box::new(ErrorImpl::Shared(shared)))
125}
126
127pub(crate) fn fix_mark(mut error: Error, mark: libyaml::Mark, path: Path) -> Error {
128 if let ErrorImpl::Message(_, none @ None) = error.0.as_mut() {
129 *none = Some(Pos {
130 mark,
131 path: path.to_string(),
132 });
133 }
134 error
135}
136
137impl Error {
138 pub(crate) fn shared(self) -> Arc<ErrorImpl> {
139 if let ErrorImpl::Shared(err) = *self.0 {
140 err
141 } else {
142 Arc::from(self.0)
143 }
144 }
145}
146
147impl From<libyaml::Error> for Error {
148 fn from(err: libyaml::Error) -> Self {
149 Error(Box::new(ErrorImpl::Libyaml(err)))
150 }
151}
152
153impl From<emitter::Error> for Error {
154 fn from(err: emitter::Error) -> Self {
155 match err {
156 emitter::Error::Libyaml(err) => Self::from(err),
157 emitter::Error::Io(err) => new(ErrorImpl::Io(err)),
158 }
159 }
160}
161
162impl StdError for Error {
163 fn source(&self) -> Option<&(dyn StdError + 'static)> {
164 self.0.source()
165 }
166}
167
168impl Display for Error {
169 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
170 self.0.display(f)
171 }
172}
173
174impl Debug for Error {
177 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
178 self.0.debug(f)
179 }
180}
181
182impl ser::Error for Error {
183 fn custom<T: Display>(msg: T) -> Self {
184 Error(Box::new(ErrorImpl::Message(msg.to_string(), None)))
185 }
186}
187
188impl de::Error for Error {
189 fn custom<T: Display>(msg: T) -> Self {
190 Error(Box::new(ErrorImpl::Message(msg.to_string(), None)))
191 }
192}
193
194impl ErrorImpl {
195 fn location(&self) -> Option<Location> {
196 self.mark().map(Location::from_mark)
197 }
198
199 fn source(&self) -> Option<&(dyn StdError + 'static)> {
200 match self {
201 ErrorImpl::Io(err) => err.source(),
202 ErrorImpl::FromUtf8(err) => err.source(),
203 ErrorImpl::Shared(err) => err.source(),
204 _ => None,
205 }
206 }
207
208 fn mark(&self) -> Option<libyaml::Mark> {
209 match self {
210 ErrorImpl::Message(_, Some(Pos { mark, path: _ }))
211 | ErrorImpl::RecursionLimitExceeded(mark)
212 | ErrorImpl::UnknownAnchor(mark) => Some(*mark),
213 ErrorImpl::Libyaml(err) => Some(err.mark()),
214 ErrorImpl::Shared(err) => err.mark(),
215 _ => None,
216 }
217 }
218
219 fn message_no_mark(&self, f: &mut fmt::Formatter) -> fmt::Result {
220 match self {
221 ErrorImpl::Message(msg, None) => f.write_str(msg),
222 ErrorImpl::Message(msg, Some(Pos { mark: _, path })) => {
223 if path != "." {
224 write!(f, "{}: ", path)?;
225 }
226 f.write_str(msg)
227 },
228 ErrorImpl::Libyaml(_) => unreachable!(),
229 ErrorImpl::Io(err) => Display::fmt(err, f),
230 ErrorImpl::FromUtf8(err) => Display::fmt(err, f),
231 ErrorImpl::EndOfStream => f.write_str("EOF while parsing a value"),
232 ErrorImpl::MoreThanOneDocument => {
233 f.write_str("deserializing from YAML containing more than one document is not supported")
234 },
235 ErrorImpl::RecursionLimitExceeded(_mark) => f.write_str("recursion limit exceeded"),
236 ErrorImpl::RepetitionLimitExceeded => f.write_str("repetition limit exceeded"),
237 ErrorImpl::BytesUnsupported => {
238 f.write_str("serialization and deserialization of bytes in YAML is not implemented")
239 },
240 ErrorImpl::UnknownAnchor(_mark) => f.write_str("unknown anchor"),
241 ErrorImpl::SerializeNestedEnum => f.write_str("serializing nested enums in YAML is not supported yet"),
242 ErrorImpl::ScalarInMerge => {
243 f.write_str("expected a mapping or list of mappings for merging, but found scalar")
244 },
245 ErrorImpl::TaggedInMerge => f.write_str("unexpected tagged value in merge"),
246 ErrorImpl::ScalarInMergeElement => f.write_str("expected a mapping for merging, but found scalar"),
247 ErrorImpl::SequenceInMergeElement => f.write_str("expected a mapping for merging, but found sequence"),
248 ErrorImpl::EmptyTag => f.write_str("empty YAML tag is not allowed"),
249 ErrorImpl::FailedToParseNumber => f.write_str("failed to parse YAML number"),
250 ErrorImpl::Shared(_) => unreachable!(),
251 }
252 }
253
254 fn display(&self, f: &mut fmt::Formatter) -> fmt::Result {
255 match self {
256 ErrorImpl::Libyaml(err) => Display::fmt(err, f),
257 ErrorImpl::Shared(err) => err.display(f),
258 _ => {
259 self.message_no_mark(f)?;
260 if let Some(mark) = self.mark() {
261 if mark.line() != 0 || mark.column() != 0 {
262 write!(f, " at {}", mark)?;
263 }
264 }
265 Ok(())
266 },
267 }
268 }
269
270 fn debug(&self, f: &mut fmt::Formatter) -> fmt::Result {
271 match self {
272 ErrorImpl::Libyaml(err) => Debug::fmt(err, f),
273 ErrorImpl::Shared(err) => err.debug(f),
274 _ => {
275 f.write_str("Error(")?;
276 struct MessageNoMark<'a>(&'a ErrorImpl);
277 impl Display for MessageNoMark<'_> {
278 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
279 self.0.message_no_mark(f)
280 }
281 }
282 let msg = MessageNoMark(self).to_string();
283 Debug::fmt(&msg, f)?;
284 if let Some(mark) = self.mark() {
285 write!(f, ", line: {}, column: {}", mark.line() + 1, mark.column() + 1,)?;
286 }
287 f.write_str(")")
288 },
289 }
290 }
291}