parsers: make stream errors more ergonomic for error processing

Jonas Schäfer created

Change summary

parsers/src/stream_error.rs | 81 +++++++++++++++++++++++++++++++++++++++
1 file changed, 81 insertions(+)

Detailed changes

parsers/src/stream_error.rs 🔗

@@ -4,6 +4,9 @@
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+use core::fmt;
+use std::error::Error;
+
 use minidom::Element;
 use xso::{AsXml, FromXml};
 
@@ -262,6 +265,39 @@ pub enum DefinedCondition {
     UnsupportedVersion,
 }
 
+impl fmt::Display for DefinedCondition {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let s = match self {
+            Self::BadFormat => "bad-format",
+            Self::BadNamespacePrefix => "bad-namespace-prefix",
+            Self::Conflict => "conflict",
+            Self::ConnectionTimeout => "connection-timeout",
+            Self::HostGone => "host-gone",
+            Self::HostUnknown => "host-unknown",
+            Self::ImproperAddressing => "improper-addressing",
+            Self::InternalServerError => "internal-server-error",
+            Self::InvalidFrom => "invalid-from",
+            Self::InvalidNamespace => "invalid-namespace",
+            Self::InvalidXml => "invalid-xml",
+            Self::NotAuthorized => "not-authorized",
+            Self::NotWellFormed => "not-well-formed",
+            Self::PolicyViolation => "policy-violation",
+            Self::RemoteConnectionFailed => "remote-connection-failed",
+            Self::Reset => "reset",
+            Self::ResourceConstraint => "resource-constraint",
+            Self::RestrictedXml => "restricted-xml",
+            Self::SeeOtherHost(ref host) => return write!(f, "see-other-host: {}", host),
+            Self::SystemShutdown => "system-shutdown",
+            Self::UndefinedCondition => "undefined-condition",
+            Self::UnsupportedEncoding => "unsupported-encoding",
+            Self::UnsupportedFeature => "unsupported-feature",
+            Self::UnsupportedStanzaType => "unsupported-stanza-type",
+            Self::UnsupportedVersion => "unsupported-version",
+        };
+        f.write_str(s)
+    }
+}
+
 /// Stream error as specified in RFC 6120.
 #[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
 #[xml(namespace = ns::STREAM, name = "error")]
@@ -281,3 +317,48 @@ pub struct StreamError {
     #[xml(element(n = ..))]
     pub application_specific: Vec<Element>,
 }
+
+impl fmt::Display for StreamError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        <DefinedCondition as fmt::Display>::fmt(&self.condition, f)?;
+        match self.text {
+            Some((_, ref text)) => write!(f, " ({:?})", text)?,
+            None => (),
+        };
+        match self.application_specific.get(0) {
+            Some(cond) => {
+                f.write_str(&String::from(cond))?;
+            }
+            None => (),
+        }
+        Ok(())
+    }
+}
+
+/// Wrapper around [`StreamError`] which implements [`std::error::Error`]
+/// with an appropriate error message.
+#[derive(FromXml, AsXml, Debug)]
+#[xml(transparent)]
+pub struct ReceivedStreamError(pub StreamError);
+
+impl fmt::Display for ReceivedStreamError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "received stream error: {}", self.0)
+    }
+}
+
+impl Error for ReceivedStreamError {}
+
+/// Wrapper around [`StreamError`] which implements [`std::error::Error`]
+/// with an appropriate error message.
+#[derive(FromXml, AsXml, Debug)]
+#[xml(transparent)]
+pub struct SentStreamError(pub StreamError);
+
+impl fmt::Display for SentStreamError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "sent stream error: {}", self.0)
+    }
+}
+
+impl Error for SentStreamError {}