use thiserror in tokio-xmpp and minidom
This commit is contained in:
parent
83635e6077
commit
de564a53b0
4 changed files with 53 additions and 186 deletions
|
|
@ -22,6 +22,7 @@ gitlab = { repository = "xmpp-rs/xmpp-rs" }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rxml = { version = "0.13.1", default-features = false, features = ["compact_str"] }
|
rxml = { version = "0.13.1", default-features = false, features = ["compact_str"] }
|
||||||
|
thiserror = "2.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = [ "std" ]
|
default = [ "std" ]
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,14 @@
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use core::{error::Error as StdError, fmt};
|
use thiserror::Error;
|
||||||
|
|
||||||
/// Our main error type.
|
/// Our main error type.
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Error from rxml parsing or writing
|
/// Error from rxml parsing or writing
|
||||||
XmlError(rxml::Error),
|
#[error("XML error: {0}")]
|
||||||
|
XmlError(#[from] rxml::Error),
|
||||||
|
|
||||||
/// I/O error from accessing the source or destination.
|
/// I/O error from accessing the source or destination.
|
||||||
///
|
///
|
||||||
|
|
@ -27,35 +28,27 @@ pub enum Error {
|
||||||
/// [`io::Error`] when using it with [`BufRead`][`io::BufRead`],
|
/// [`io::Error`] when using it with [`BufRead`][`io::BufRead`],
|
||||||
/// any rxml errors will still be reported through the
|
/// any rxml errors will still be reported through the
|
||||||
/// [`XmlError`][`Self::XmlError`] variant.
|
/// [`XmlError`][`Self::XmlError`] variant.
|
||||||
|
#[error("I/O error: {0}")]
|
||||||
Io(io::Error),
|
Io(io::Error),
|
||||||
|
|
||||||
/// An error which is returned when the end of the document was reached prematurely.
|
/// An error which is returned when the end of the document was reached prematurely.
|
||||||
|
#[error("the end of the document has been reached prematurely")]
|
||||||
EndOfDocument,
|
EndOfDocument,
|
||||||
|
|
||||||
/// An error which is returned when an element being serialized doesn't contain a prefix
|
/// An error which is returned when an element being serialized doesn't contain a prefix
|
||||||
/// (be it None or Some(_)).
|
/// (be it None or Some(_)).
|
||||||
|
#[error("the prefix is invalid")]
|
||||||
InvalidPrefix,
|
InvalidPrefix,
|
||||||
|
|
||||||
/// An error which is returned when an element doesn't contain a namespace
|
/// An error which is returned when an element doesn't contain a namespace
|
||||||
|
#[error("the XML element is missing a namespace")]
|
||||||
MissingNamespace,
|
MissingNamespace,
|
||||||
|
|
||||||
/// An error which is returned when a prefixed is defined twice
|
/// An error which is returned when a prefixed is defined twice
|
||||||
|
#[error("the prefix is already defined")]
|
||||||
DuplicatePrefix,
|
DuplicatePrefix,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StdError for Error {
|
|
||||||
fn cause(&self) -> Option<&dyn StdError> {
|
|
||||||
match self {
|
|
||||||
Error::XmlError(e) => Some(e),
|
|
||||||
Error::Io(e) => Some(e),
|
|
||||||
Error::EndOfDocument
|
|
||||||
| Error::InvalidPrefix
|
|
||||||
| Error::MissingNamespace
|
|
||||||
| Error::DuplicatePrefix => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<io::Error> for Error {
|
impl From<io::Error> for Error {
|
||||||
fn from(other: io::Error) -> Self {
|
fn from(other: io::Error) -> Self {
|
||||||
match other.downcast::<rxml::Error>() {
|
match other.downcast::<rxml::Error>() {
|
||||||
|
|
@ -65,27 +58,6 @@ impl From<io::Error> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
Error::XmlError(e) => write!(fmt, "XML error: {e}"),
|
|
||||||
Error::Io(e) => write!(fmt, "I/O error: {e}"),
|
|
||||||
Error::EndOfDocument => {
|
|
||||||
write!(fmt, "the end of the document has been reached prematurely")
|
|
||||||
}
|
|
||||||
Error::InvalidPrefix => write!(fmt, "the prefix is invalid"),
|
|
||||||
Error::MissingNamespace => write!(fmt, "the XML element is missing a namespace",),
|
|
||||||
Error::DuplicatePrefix => write!(fmt, "the prefix is already defined"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<rxml::Error> for Error {
|
|
||||||
fn from(err: rxml::Error) -> Error {
|
|
||||||
Error::XmlError(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<rxml::strings::Error> for Error {
|
impl From<rxml::strings::Error> for Error {
|
||||||
fn from(err: rxml::strings::Error) -> Error {
|
fn from(err: rxml::strings::Error) -> Error {
|
||||||
rxml::error::Error::from(err).into()
|
rxml::error::Error::from(err).into()
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ rxml = { version = "0.13.1", features = ["compact_str"] }
|
||||||
rand = "0.9"
|
rand = "0.9"
|
||||||
syntect = { version = "5", optional = true }
|
syntect = { version = "5", optional = true }
|
||||||
pin-project-lite = { version = "0.2" }
|
pin-project-lite = { version = "0.2" }
|
||||||
|
thiserror = "2.0"
|
||||||
# same repository dependencies
|
# same repository dependencies
|
||||||
sasl = { version = "0.5", path = "../sasl" }
|
sasl = { version = "0.5", path = "../sasl" }
|
||||||
xmpp-parsers = { version = "0.21", path = "../parsers", features = [ "log" ] }
|
xmpp-parsers = { version = "0.21", path = "../parsers", features = [ "log" ] }
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
use core::{error::Error as StdError, fmt, net::AddrParseError, str::Utf8Error};
|
use core::{fmt, net::AddrParseError, str::Utf8Error};
|
||||||
#[cfg(feature = "dns")]
|
#[cfg(feature = "dns")]
|
||||||
use hickory_resolver::{proto::ProtoError as DnsProtoError, ResolveError as DnsResolveError};
|
use hickory_resolver::{proto::ProtoError as DnsProtoError, ResolveError as DnsResolveError};
|
||||||
use sasl::client::MechanismError as SaslMechanismError;
|
use sasl::client::MechanismError as SaslMechanismError;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
use xmpp_parsers::stream_error::ReceivedStreamError;
|
use xmpp_parsers::stream_error::ReceivedStreamError;
|
||||||
|
|
||||||
|
|
@ -12,110 +13,62 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Top-level error type
|
/// Top-level error type
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// I/O error
|
/// I/O error
|
||||||
Io(io::Error),
|
#[error("I/O error: {0}")]
|
||||||
|
Io(#[from] io::Error),
|
||||||
/// Error parsing Jabber-Id
|
/// Error parsing Jabber-Id
|
||||||
JidParse(jid::Error),
|
#[error("JID parse error: {0}")]
|
||||||
|
JidParse(#[from] jid::Error),
|
||||||
/// Protocol-level error
|
/// Protocol-level error
|
||||||
Protocol(ProtocolError),
|
#[error("protocol error: {0}")]
|
||||||
|
Protocol(#[from] ProtocolError),
|
||||||
/// Authentication error
|
/// Authentication error
|
||||||
Auth(AuthError),
|
#[error("authentication error: {0}")]
|
||||||
|
Auth(#[from] AuthError),
|
||||||
/// Connection closed
|
/// Connection closed
|
||||||
|
#[error("disconnected")]
|
||||||
Disconnected,
|
Disconnected,
|
||||||
/// Should never happen
|
/// Should never happen
|
||||||
|
#[error("invalid state")]
|
||||||
InvalidState,
|
InvalidState,
|
||||||
/// Fmt error
|
/// Fmt error
|
||||||
Fmt(fmt::Error),
|
#[error("fmt error: {0}")]
|
||||||
|
Fmt(#[from] fmt::Error),
|
||||||
/// Utf8 error
|
/// Utf8 error
|
||||||
Utf8(Utf8Error),
|
#[error("UTF-8 error: {0}")]
|
||||||
|
Utf8(#[from] Utf8Error),
|
||||||
/// Error specific to ServerConnector impl
|
/// Error specific to ServerConnector impl
|
||||||
|
#[error("connection error: {0}")]
|
||||||
Connection(Box<dyn ServerConnectorError>),
|
Connection(Box<dyn ServerConnectorError>),
|
||||||
/// DNS protocol error
|
/// DNS protocol error
|
||||||
#[cfg(feature = "dns")]
|
#[cfg(feature = "dns")]
|
||||||
Dns(DnsProtoError),
|
#[error("{0:?}")]
|
||||||
|
Dns(#[from] DnsProtoError),
|
||||||
/// DNS resolution error
|
/// DNS resolution error
|
||||||
#[cfg(feature = "dns")]
|
#[cfg(feature = "dns")]
|
||||||
Resolve(DnsResolveError),
|
#[error("{0:?}")]
|
||||||
|
Resolve(#[from] DnsResolveError),
|
||||||
/// DNS label conversion error, no details available from module
|
/// DNS label conversion error, no details available from module
|
||||||
/// `idna`
|
/// `idna`
|
||||||
#[cfg(feature = "dns")]
|
#[cfg(feature = "dns")]
|
||||||
|
#[error("IDNA error")]
|
||||||
Idna,
|
Idna,
|
||||||
/// Invalid IP/Port address
|
/// Invalid IP/Port address
|
||||||
Addr(AddrParseError),
|
#[error("wrong network address: {0}")]
|
||||||
|
Addr(#[from] AddrParseError),
|
||||||
/// Received a stream error
|
/// Received a stream error
|
||||||
|
#[error("{0}")]
|
||||||
StreamError(ReceivedStreamError),
|
StreamError(ReceivedStreamError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
Error::Io(e) => write!(fmt, "IO error: {}", e),
|
|
||||||
Error::Connection(e) => write!(fmt, "connection error: {}", e),
|
|
||||||
Error::JidParse(e) => write!(fmt, "jid parse error: {}", e),
|
|
||||||
Error::Protocol(e) => write!(fmt, "protocol error: {}", e),
|
|
||||||
Error::Auth(e) => write!(fmt, "authentication error: {}", e),
|
|
||||||
Error::Disconnected => write!(fmt, "disconnected"),
|
|
||||||
Error::InvalidState => write!(fmt, "invalid state"),
|
|
||||||
Error::Fmt(e) => write!(fmt, "Fmt error: {}", e),
|
|
||||||
Error::Utf8(e) => write!(fmt, "Utf8 error: {}", e),
|
|
||||||
#[cfg(feature = "dns")]
|
|
||||||
Error::Dns(e) => write!(fmt, "{:?}", e),
|
|
||||||
#[cfg(feature = "dns")]
|
|
||||||
Error::Resolve(e) => write!(fmt, "{:?}", e),
|
|
||||||
#[cfg(feature = "dns")]
|
|
||||||
Error::Idna => write!(fmt, "IDNA error"),
|
|
||||||
Error::Addr(e) => write!(fmt, "Wrong network address: {e}"),
|
|
||||||
Error::StreamError(e) => write!(fmt, "{e}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StdError for Error {}
|
|
||||||
|
|
||||||
impl From<io::Error> for Error {
|
|
||||||
fn from(e: io::Error) -> Self {
|
|
||||||
Error::Io(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: ServerConnectorError + 'static> From<T> for Error {
|
impl<T: ServerConnectorError + 'static> From<T> for Error {
|
||||||
fn from(e: T) -> Self {
|
fn from(e: T) -> Self {
|
||||||
Error::Connection(Box::new(e))
|
Error::Connection(Box::new(e))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<jid::Error> for Error {
|
|
||||||
fn from(e: jid::Error) -> Self {
|
|
||||||
Error::JidParse(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ProtocolError> for Error {
|
|
||||||
fn from(e: ProtocolError) -> Self {
|
|
||||||
Error::Protocol(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<AuthError> for Error {
|
|
||||||
fn from(e: AuthError) -> Self {
|
|
||||||
Error::Auth(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<fmt::Error> for Error {
|
|
||||||
fn from(e: fmt::Error) -> Self {
|
|
||||||
Error::Fmt(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Utf8Error> for Error {
|
|
||||||
fn from(e: Utf8Error) -> Self {
|
|
||||||
Error::Utf8(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "dns")]
|
#[cfg(feature = "dns")]
|
||||||
impl From<idna::Errors> for Error {
|
impl From<idna::Errors> for Error {
|
||||||
fn from(_e: idna::Errors) -> Self {
|
fn from(_e: idna::Errors) -> Self {
|
||||||
|
|
@ -123,26 +76,6 @@ impl From<idna::Errors> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "dns")]
|
|
||||||
impl From<DnsResolveError> for Error {
|
|
||||||
fn from(e: DnsResolveError) -> Error {
|
|
||||||
Error::Resolve(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "dns")]
|
|
||||||
impl From<DnsProtoError> for Error {
|
|
||||||
fn from(e: DnsProtoError) -> Error {
|
|
||||||
Error::Dns(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<AddrParseError> for Error {
|
|
||||||
fn from(e: AddrParseError) -> Error {
|
|
||||||
Error::Addr(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<RecvFeaturesError> for Error {
|
impl From<RecvFeaturesError> for Error {
|
||||||
fn from(e: RecvFeaturesError) -> Self {
|
fn from(e: RecvFeaturesError) -> Self {
|
||||||
match e {
|
match e {
|
||||||
|
|
@ -153,87 +86,47 @@ impl From<RecvFeaturesError> for Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// XMPP protocol-level error
|
/// XMPP protocol-level error
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Error)]
|
||||||
pub enum ProtocolError {
|
pub enum ProtocolError {
|
||||||
/// XML parser error
|
/// XML parser error
|
||||||
Parser(minidom::Error),
|
#[error("XML parser error: {0}")]
|
||||||
|
Parser(#[from] minidom::Error),
|
||||||
/// Error with expected stanza schema
|
/// Error with expected stanza schema
|
||||||
Parsers(xso::error::Error),
|
#[error("error with expected stanza schema: {0}")]
|
||||||
|
Parsers(#[from] xso::error::Error),
|
||||||
/// No TLS available
|
/// No TLS available
|
||||||
|
#[error("no TLS available")]
|
||||||
NoTls,
|
NoTls,
|
||||||
/// Invalid response to resource binding
|
/// Invalid response to resource binding
|
||||||
|
#[error("invalid response to resource binding")]
|
||||||
InvalidBindResponse,
|
InvalidBindResponse,
|
||||||
/// No xmlns attribute in <stream:stream>
|
/// No xmlns attribute in <stream:stream>
|
||||||
|
#[error("no xmlns attribute in <stream:stream>")]
|
||||||
NoStreamNamespace,
|
NoStreamNamespace,
|
||||||
/// No id attribute in <stream:stream>
|
/// No id attribute in <stream:stream>
|
||||||
|
#[error("no id attribute in <stream:stream>")]
|
||||||
NoStreamId,
|
NoStreamId,
|
||||||
/// Encountered an unexpected XML token
|
/// Encountered an unexpected XML token
|
||||||
|
#[error("encountered an unexpected XML token")]
|
||||||
InvalidToken,
|
InvalidToken,
|
||||||
/// Unexpected <stream:stream> (shouldn't occur)
|
/// Unexpected <stream:stream> (shouldn't occur)
|
||||||
|
#[error("unexpected <stream:stream>")]
|
||||||
InvalidStreamStart,
|
InvalidStreamStart,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ProtocolError {
|
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
ProtocolError::Parser(e) => write!(fmt, "XML parser error: {}", e),
|
|
||||||
ProtocolError::Parsers(e) => write!(fmt, "error with expected stanza schema: {}", e),
|
|
||||||
ProtocolError::NoTls => write!(fmt, "no TLS available"),
|
|
||||||
ProtocolError::InvalidBindResponse => {
|
|
||||||
write!(fmt, "invalid response to resource binding")
|
|
||||||
}
|
|
||||||
ProtocolError::NoStreamNamespace => {
|
|
||||||
write!(fmt, "no xmlns attribute in <stream:stream>")
|
|
||||||
}
|
|
||||||
ProtocolError::NoStreamId => write!(fmt, "no id attribute in <stream:stream>"),
|
|
||||||
ProtocolError::InvalidToken => write!(fmt, "encountered an unexpected XML token"),
|
|
||||||
ProtocolError::InvalidStreamStart => write!(fmt, "unexpected <stream:stream>"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StdError for ProtocolError {}
|
|
||||||
|
|
||||||
impl From<minidom::Error> for ProtocolError {
|
|
||||||
fn from(e: minidom::Error) -> Self {
|
|
||||||
ProtocolError::Parser(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<minidom::Error> for Error {
|
|
||||||
fn from(e: minidom::Error) -> Self {
|
|
||||||
ProtocolError::Parser(e).into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<xso::error::Error> for ProtocolError {
|
|
||||||
fn from(e: xso::error::Error) -> Self {
|
|
||||||
ProtocolError::Parsers(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Authentication error
|
/// Authentication error
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Error)]
|
||||||
pub enum AuthError {
|
pub enum AuthError {
|
||||||
/// No matching SASL mechanism available
|
/// No matching SASL mechanism available
|
||||||
|
#[error("no matching SASL mechanism available")]
|
||||||
NoMechanism,
|
NoMechanism,
|
||||||
/// Local SASL implementation error
|
/// Local SASL implementation error
|
||||||
|
#[error("local SASL implementation error: {0}")]
|
||||||
Sasl(SaslMechanismError),
|
Sasl(SaslMechanismError),
|
||||||
/// Failure from server
|
/// Failure from server
|
||||||
|
#[error("failure from the server: {0:?}")]
|
||||||
Fail(SaslDefinedCondition),
|
Fail(SaslDefinedCondition),
|
||||||
/// Component authentication failure
|
/// Component authentication failure
|
||||||
|
#[error("component authentication failure")]
|
||||||
ComponentFail,
|
ComponentFail,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StdError for AuthError {}
|
|
||||||
|
|
||||||
impl fmt::Display for AuthError {
|
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
AuthError::NoMechanism => write!(fmt, "no matching SASL mechanism available"),
|
|
||||||
AuthError::Sasl(s) => write!(fmt, "local SASL implementation error: {}", s),
|
|
||||||
AuthError::Fail(c) => write!(fmt, "failure from the server: {:?}", c),
|
|
||||||
AuthError::ComponentFail => write!(fmt, "component authentication failure"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue