use peanuts::{ element::{FromElement, IntoElement}, DeserializeError, Element, XML_NS, }; use thiserror::Error; pub const XMLNS: &str = "urn:ietf:params:xml:ns:xmpp-streams"; #[derive(Error, Clone, Debug)] pub enum Error { #[error("bad format")] BadFormat, #[error("bad namespace prefix")] BadNamespacePrefix, #[error("conflict")] Conflict, #[error("connection timeout")] ConnectionTimeout, #[error("host gone")] HostGone, #[error("host unknown")] HostUnknown, #[error("improper addressing")] ImproperAddressing, #[error("internal server error")] InternalServerError, #[error("invalid from")] InvalidFrom, #[error("invalid id")] InvalidId, #[error("invalid namespace")] InvalidNamespace, #[error("invalid xml")] InvalidXml, #[error("not authorized")] NotAuthorized, #[error("not well formed")] NotWellFormed, #[error("policy violation")] PolicyViolation, #[error("remote connection failed")] RemoteConnectionFailed, #[error("reset")] Reset, #[error("resource constraint")] ResourceConstraint, #[error("restricted xml")] RestrictedXml, #[error("see other host: {0:?}")] SeeOtherHost(Option), #[error("system shutdown")] SystemShutdown, #[error("undefined condition")] UndefinedCondition, #[error("unsupported encoding")] UnsupportedEncoding, #[error("unsupported stanza type")] UnsupportedStanzaType, #[error("unsupported version")] UnsupportedVersion, } impl FromElement for Error { fn from_element(mut element: peanuts::Element) -> peanuts::element::DeserializeResult { let error; match element.identify() { (Some(XMLNS), "bad-format") => error = Error::BadFormat, (Some(XMLNS), "bad-namespace-prefix") => error = Error::BadNamespacePrefix, (Some(XMLNS), "conflict") => error = Error::Conflict, (Some(XMLNS), "connection-timeout") => error = Error::ConnectionTimeout, (Some(XMLNS), "host-gone") => error = Error::HostGone, (Some(XMLNS), "host-unknown") => error = Error::HostUnknown, (Some(XMLNS), "improper-addressing") => error = Error::ImproperAddressing, (Some(XMLNS), "internal-server-error") => error = Error::InternalServerError, (Some(XMLNS), "invalid-from") => error = Error::InvalidFrom, (Some(XMLNS), "invalid-id") => error = Error::InvalidId, (Some(XMLNS), "invalid-namespace") => error = Error::InvalidNamespace, (Some(XMLNS), "invalid-xml") => error = Error::InvalidXml, (Some(XMLNS), "not-authorized") => error = Error::NotAuthorized, (Some(XMLNS), "not-well-formed") => error = Error::NotWellFormed, (Some(XMLNS), "policy-violation") => error = Error::PolicyViolation, (Some(XMLNS), "remote-connection-failed") => error = Error::RemoteConnectionFailed, (Some(XMLNS), "reset") => error = Error::Reset, (Some(XMLNS), "resource-constraint") => error = Error::ResourceConstraint, (Some(XMLNS), "restricted-xml") => error = Error::RestrictedXml, (Some(XMLNS), "see-other-host") => { return Ok(Error::SeeOtherHost(element.pop_value_opt()?)) } (Some(XMLNS), "system-shutdown") => error = Error::SystemShutdown, (Some(XMLNS), "undefined-condition") => error = Error::UndefinedCondition, (Some(XMLNS), "unsupported-encoding") => error = Error::UnsupportedEncoding, (Some(XMLNS), "unsupported-stanza-type") => error = Error::UnsupportedStanzaType, (Some(XMLNS), "unsupported-version") => error = Error::UnsupportedVersion, _ => return Err(DeserializeError::UnexpectedElement(element)), } element.no_more_content()?; return Ok(error); } } impl IntoElement for Error { fn builder(&self) -> peanuts::element::ElementBuilder { match self { Error::BadFormat => Element::builder("bad-format", Some(XMLNS)), Error::BadNamespacePrefix => Element::builder("bad-namespace-prefix", Some(XMLNS)), Error::Conflict => Element::builder("conflict", Some(XMLNS)), Error::ConnectionTimeout => Element::builder("connection-timeout", Some(XMLNS)), Error::HostGone => Element::builder("host-gone", Some(XMLNS)), Error::HostUnknown => Element::builder("host-unknown", Some(XMLNS)), Error::ImproperAddressing => Element::builder("improper-addressing", Some(XMLNS)), Error::InternalServerError => Element::builder("internal-server-error", Some(XMLNS)), Error::InvalidFrom => Element::builder("invalid-from", Some(XMLNS)), Error::InvalidId => Element::builder("invalid-id", Some(XMLNS)), Error::InvalidNamespace => Element::builder("invalid-namespace", Some(XMLNS)), Error::InvalidXml => Element::builder("invalid-xml", Some(XMLNS)), Error::NotAuthorized => Element::builder("not-authorized", Some(XMLNS)), Error::NotWellFormed => Element::builder("not-well-formed", Some(XMLNS)), Error::PolicyViolation => Element::builder("policy-violation", Some(XMLNS)), Error::RemoteConnectionFailed => { Element::builder("remote-connection-failed", Some(XMLNS)) } Error::Reset => Element::builder("reset", Some(XMLNS)), Error::ResourceConstraint => Element::builder("resource-constraint", Some(XMLNS)), Error::RestrictedXml => Element::builder("restricted-xml", Some(XMLNS)), Error::SeeOtherHost(h) => { Element::builder("see-other-host", Some(XMLNS)).push_text_opt(h.clone()) } Error::SystemShutdown => Element::builder("system-shutdown", Some(XMLNS)), Error::UndefinedCondition => Element::builder("undefined-condition", Some(XMLNS)), Error::UnsupportedEncoding => Element::builder("unsupported-encoding", Some(XMLNS)), Error::UnsupportedStanzaType => { Element::builder("unsupported-stanza-type", Some(XMLNS)) } Error::UnsupportedVersion => Element::builder("unsupported-version", Some(XMLNS)), } } } #[derive(Clone, Debug)] pub struct Text { text: Option, lang: Option, } impl FromElement for Text { fn from_element(mut element: peanuts::Element) -> peanuts::element::DeserializeResult { element.check_name("text")?; element.check_name(XMLNS)?; let lang = element.attribute_opt_namespaced("lang", XML_NS)?; let text = element.pop_value_opt()?; Ok(Text { lang, text }) } } impl IntoElement for Text { fn builder(&self) -> peanuts::element::ElementBuilder { Element::builder("text", Some(XMLNS)) .push_attribute_opt_namespaced(XML_NS, "lang", self.lang.clone()) .push_text_opt(self.text.clone()) } }