1// Copyright (c) 2017-2018 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7use std::error::Error as StdError;
8use std::fmt;
9
10/// Contains one of the potential errors triggered while parsing an
11/// [Element](../struct.Element.html) into a specialised struct.
12#[derive(Debug)]
13pub enum Error {
14 /// The usual error when parsing something.
15 ///
16 /// TODO: use a structured error so the user can report it better, instead
17 /// of a freeform string.
18 ParseError(&'static str),
19
20 /// Element local-name/namespace mismatch
21 ///
22 /// Returns the original element unaltered, as well as the expected ns and
23 /// local-name.
24 TypeMismatch(&'static str, &'static str, crate::Element),
25
26 /// Generated when some base64 content fails to decode, usually due to
27 /// extra characters.
28 Base64Error(base64::DecodeError),
29
30 /// Generated when text which should be an integer fails to parse.
31 ParseIntError(std::num::ParseIntError),
32
33 /// Generated when text which should be a string fails to parse.
34 ParseStringError(std::string::ParseError),
35
36 /// Generated when text which should be an IP address (IPv4 or IPv6) fails
37 /// to parse.
38 ParseAddrError(std::net::AddrParseError),
39
40 /// Generated when text which should be a [JID](../../jid/struct.Jid.html)
41 /// fails to parse.
42 JidParseError(jid::Error),
43
44 /// Generated when text which should be a
45 /// [DateTime](../date/struct.DateTime.html) fails to parse.
46 ChronoParseError(chrono::ParseError),
47}
48
49impl Error {
50 /// Converts the TypeMismatch error to a generic ParseError
51 ///
52 /// This must be used when TryFrom is called on children to avoid confusing
53 /// user code which assumes that TypeMismatch refers to the top level
54 /// element only.
55 pub(crate) fn hide_type_mismatch(self) -> Self {
56 match self {
57 Error::TypeMismatch(..) => Error::ParseError("Unexpected child element"),
58 other => other,
59 }
60 }
61}
62
63impl StdError for Error {
64 fn cause(&self) -> Option<&dyn StdError> {
65 match self {
66 Error::ParseError(_) | Error::TypeMismatch(..) => None,
67 Error::Base64Error(e) => Some(e),
68 Error::ParseIntError(e) => Some(e),
69 Error::ParseStringError(e) => Some(e),
70 Error::ParseAddrError(e) => Some(e),
71 Error::JidParseError(e) => Some(e),
72 Error::ChronoParseError(e) => Some(e),
73 }
74 }
75}
76
77impl fmt::Display for Error {
78 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
79 match self {
80 Error::ParseError(s) => write!(fmt, "parse error: {}", s),
81 Error::TypeMismatch(ns, localname, element) => write!(
82 fmt,
83 "element type mismatch: expected {{{}}}{}, got {{{}}}{}",
84 ns,
85 localname,
86 element.ns(),
87 element.name()
88 ),
89 Error::Base64Error(e) => write!(fmt, "base64 error: {}", e),
90 Error::ParseIntError(e) => write!(fmt, "integer parsing error: {}", e),
91 Error::ParseStringError(e) => write!(fmt, "string parsing error: {}", e),
92 Error::ParseAddrError(e) => write!(fmt, "IP address parsing error: {}", e),
93 Error::JidParseError(e) => write!(fmt, "JID parsing error: {}", e),
94 Error::ChronoParseError(e) => write!(fmt, "time parsing error: {}", e),
95 }
96 }
97}
98
99impl From<base64::DecodeError> for Error {
100 fn from(err: base64::DecodeError) -> Error {
101 Error::Base64Error(err)
102 }
103}
104
105impl From<std::num::ParseIntError> for Error {
106 fn from(err: std::num::ParseIntError) -> Error {
107 Error::ParseIntError(err)
108 }
109}
110
111impl From<std::string::ParseError> for Error {
112 fn from(err: std::string::ParseError) -> Error {
113 Error::ParseStringError(err)
114 }
115}
116
117impl From<std::net::AddrParseError> for Error {
118 fn from(err: std::net::AddrParseError) -> Error {
119 Error::ParseAddrError(err)
120 }
121}
122
123impl From<jid::Error> for Error {
124 fn from(err: jid::Error) -> Error {
125 Error::JidParseError(err)
126 }
127}
128
129impl From<chrono::ParseError> for Error {
130 fn from(err: chrono::ParseError) -> Error {
131 Error::ChronoParseError(err)
132 }
133}