error.rs

  1/*!
  2# Error types for XML parsing
  3
  4This module contains the error types used throughout the `xso` crate.
  5*/
  6
  7// Copyright (c) 2024 Jonas Schäfer <jonas@zombofant.net>
  8//
  9// This Source Code Form is subject to the terms of the Mozilla Public
 10// License, v. 2.0. If a copy of the MPL was not distributed with this
 11// file, You can obtain one at http://mozilla.org/MPL/2.0/.
 12use core::fmt;
 13
 14use rxml::error::XmlError;
 15
 16/// Error variants generated while parsing or serialising XML data.
 17#[derive(Debug)]
 18pub enum Error {
 19    /// Invalid XML data encountered
 20    XmlError(XmlError),
 21
 22    /// Attempt to parse text data failed with the provided nested error.
 23    TextParseError(Box<dyn std::error::Error + Send + Sync + 'static>),
 24
 25    /// Generic, unspecified other error.
 26    Other(&'static str),
 27
 28    /// An element header did not match an expected element.
 29    ///
 30    /// This is only rarely generated: most of the time, a mismatch of element
 31    /// types is reported as either an unexpected or a missing child element,
 32    /// errors which are generally more specific.
 33    TypeMismatch,
 34}
 35
 36impl Error {
 37    /// Convenience function to create a [`Self::TextParseError`] variant.
 38    ///
 39    /// This includes the `Box::new(.)` call, making it directly usable as
 40    /// argument to [`Result::map_err`].
 41    pub fn text_parse_error<T: std::error::Error + Send + Sync + 'static>(e: T) -> Self {
 42        Self::TextParseError(Box::new(e))
 43    }
 44}
 45
 46impl fmt::Display for Error {
 47    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 48        match self {
 49            Self::XmlError(ref e) => write!(f, "xml parse error: {}", e),
 50            Self::TextParseError(ref e) => write!(f, "text parse error: {}", e),
 51            Self::TypeMismatch => f.write_str("mismatch between expected and actual XML data"),
 52            Self::Other(msg) => f.write_str(msg),
 53        }
 54    }
 55}
 56
 57impl std::error::Error for Error {
 58    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
 59        match self {
 60            Self::XmlError(ref e) => Some(e),
 61            Self::TextParseError(ref e) => Some(&**e),
 62            _ => None,
 63        }
 64    }
 65}
 66
 67impl From<rxml::error::XmlError> for Error {
 68    fn from(other: rxml::error::XmlError) -> Error {
 69        Error::XmlError(other)
 70    }
 71}
 72
 73impl From<rxml::strings::Error> for Error {
 74    fn from(other: rxml::strings::Error) -> Error {
 75        Error::XmlError(other.into())
 76    }
 77}
 78
 79impl From<core::convert::Infallible> for Error {
 80    fn from(other: core::convert::Infallible) -> Self {
 81        match other {}
 82    }
 83}
 84
 85/// Error returned from
 86/// [`FromXml::from_events`][`crate::FromXml::from_events`].
 87#[derive(Debug)]
 88pub enum FromEventsError {
 89    /// The `name` and/or `attrs` passed to `FromXml::from_events` did not
 90    /// match the element's type.
 91    Mismatch {
 92        /// The `name` passed to `from_events`.
 93        name: rxml::QName,
 94
 95        /// The `attrs` passed to `from_events`.
 96        attrs: rxml::AttrMap,
 97    },
 98
 99    /// The `name` and `attrs` passed to `FromXml::from_events` matched the
100    /// element's type, but the data was invalid. Details are in the inner
101    /// error.
102    Invalid(Error),
103}
104
105impl From<Error> for FromEventsError {
106    fn from(other: Error) -> Self {
107        Self::Invalid(other)
108    }
109}
110
111impl From<core::convert::Infallible> for FromEventsError {
112    fn from(other: core::convert::Infallible) -> Self {
113        match other {}
114    }
115}
116
117impl fmt::Display for FromEventsError {
118    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
119        match self {
120            Self::Mismatch { .. } => f.write_str("element header did not match"),
121            Self::Invalid(ref e) => fmt::Display::fmt(e, f),
122        }
123    }
124}
125
126impl std::error::Error for FromEventsError {
127    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
128        match self {
129            Self::Mismatch { .. } => None,
130            Self::Invalid(ref e) => Some(e),
131        }
132    }
133}
134
135impl From<Error> for Result<minidom::Element, Error> {
136    fn from(other: Error) -> Self {
137        Self::Err(other)
138    }
139}
140
141/// Error returned by the `TryFrom<Element>` implementations.
142#[derive(Debug)]
143pub enum FromElementError {
144    /// The XML element header did not match the expectations of the type
145    /// implementing `TryFrom`.
146    ///
147    /// Contains the original `Element` unmodified.
148    Mismatch(minidom::Element),
149
150    /// During processing of the element, an (unrecoverable) error occured.
151    Invalid(Error),
152}
153
154impl fmt::Display for FromElementError {
155    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
156        match self {
157            Self::Mismatch(ref el) => write!(
158                f,
159                "expected different XML element (got {} in namespace {})",
160                el.name(),
161                el.ns()
162            ),
163            Self::Invalid(ref e) => fmt::Display::fmt(e, f),
164        }
165    }
166}
167
168impl std::error::Error for FromElementError {
169    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
170        match self {
171            Self::Mismatch(_) => None,
172            Self::Invalid(ref e) => Some(e),
173        }
174    }
175}
176
177impl From<Result<minidom::Element, Error>> for FromElementError {
178    fn from(other: Result<minidom::Element, Error>) -> Self {
179        match other {
180            Ok(v) => Self::Mismatch(v),
181            Err(e) => Self::Invalid(e),
182        }
183    }
184}
185
186impl From<Error> for FromElementError {
187    fn from(other: Error) -> Self {
188        Self::Invalid(other)
189    }
190}
191
192impl From<FromElementError> for Error {
193    fn from(other: FromElementError) -> Self {
194        match other {
195            FromElementError::Invalid(e) => e,
196            FromElementError::Mismatch(..) => Self::TypeMismatch,
197        }
198    }
199}
200
201impl From<core::convert::Infallible> for FromElementError {
202    fn from(other: core::convert::Infallible) -> Self {
203        match other {}
204    }
205}