From 04d90f22ee306cf8c251e77812b55ea69044dc1f Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Sat, 6 May 2017 21:13:53 +0100 Subject: [PATCH] stanza_error: Switch to Into/TryFrom. --- src/iq.rs | 20 +++--- src/message.rs | 8 +-- src/presence.rs | 8 +-- src/stanza_error.rs | 165 +++++++++++++++++++++++--------------------- 4 files changed, 102 insertions(+), 99 deletions(-) diff --git a/src/iq.rs b/src/iq.rs index f48026a..0e0aca7 100644 --- a/src/iq.rs +++ b/src/iq.rs @@ -16,7 +16,7 @@ use error::Error; use ns; -use stanza_error; +use stanza_error::StanzaError; use disco::Disco; use ibb::IBB; use jingle::Jingle; @@ -42,7 +42,7 @@ pub enum IqType { Get(IqPayloadType), Set(IqPayloadType), Result(Option), - Error(stanza_error::StanzaError), + Error(StanzaError), } impl IntoAttributeValue for IqType { @@ -90,7 +90,7 @@ pub fn parse_iq(root: &Element) -> Result { if error_payload.is_some() { return Err(Error::ParseError("Wrong number of children in iq element.")); } - error_payload = Some(stanza_error::parse_stanza_error(elem)?); + error_payload = Some(StanzaError::try_from(elem)?); } else if root.children().collect::>().len() != 2 { return Err(Error::ParseError("Wrong number of children in iq element.")); } @@ -171,7 +171,7 @@ pub fn serialise(iq: &Iq) -> Element { IqType::Get(IqPayloadType::XML(elem)) | IqType::Set(IqPayloadType::XML(elem)) | IqType::Result(Some(IqPayloadType::XML(elem))) => elem, - IqType::Error(error) => stanza_error::serialise(&error), + IqType::Error(error) => (&error).into(), IqType::Get(IqPayloadType::Parsed(payload)) | IqType::Set(IqPayloadType::Parsed(payload)) | IqType::Result(Some(IqPayloadType::Parsed(payload))) => serialise_payload(&payload), @@ -183,11 +183,9 @@ pub fn serialise(iq: &Iq) -> Element { #[cfg(test)] mod tests { - use minidom::Element; - use error::Error; + use super::*; use iq; - use stanza_error; - use disco; + use stanza_error::{ErrorType, DefinedCondition}; #[test] fn test_require_type() { @@ -275,9 +273,9 @@ mod tests { assert_eq!(iq.id, None); match iq.payload { iq::IqType::Error(error) => { - assert_eq!(error.type_, stanza_error::ErrorType::Cancel); + assert_eq!(error.type_, ErrorType::Cancel); assert_eq!(error.by, None); - assert_eq!(error.defined_condition, stanza_error::DefinedCondition::ServiceUnavailable); + assert_eq!(error.defined_condition, DefinedCondition::ServiceUnavailable); assert_eq!(error.texts.len(), 0); assert_eq!(error.other, None); }, @@ -314,7 +312,7 @@ mod tests { let elem: Element = "".parse().unwrap(); let iq = iq::parse_iq(&elem).unwrap(); assert!(match iq.payload { - iq::IqType::Get(iq::IqPayloadType::Parsed(iq::IqPayload::Disco(disco::Disco { .. }))) => true, + IqType::Get(IqPayloadType::Parsed(IqPayload::Disco(Disco { .. }))) => true, _ => false, }); } diff --git a/src/message.rs b/src/message.rs index ce6622a..ee2c644 100644 --- a/src/message.rs +++ b/src/message.rs @@ -16,7 +16,7 @@ use error::Error; use ns; use body; -use stanza_error; +use stanza_error::StanzaError; use chatstates::ChatState; use receipts::Receipt; use delay::Delay; @@ -28,7 +28,7 @@ use eme::ExplicitMessageEncryption; #[derive(Debug, Clone)] pub enum MessagePayload { Body(body::Body), - StanzaError(stanza_error::StanzaError), + StanzaError(StanzaError), ChatState(ChatState), Receipt(Receipt), Delay(Delay), @@ -113,7 +113,7 @@ pub fn parse_message(root: &Element) -> Result { for elem in root.children() { let payload = if let Ok(body) = body::parse_body(elem) { Some(MessagePayload::Body(body)) - } else if let Ok(stanza_error) = stanza_error::parse_stanza_error(elem) { + } else if let Ok(stanza_error) = StanzaError::try_from(elem) { Some(MessagePayload::StanzaError(stanza_error)) } else if let Ok(chatstate) = ChatState::try_from(elem) { Some(MessagePayload::ChatState(chatstate)) @@ -147,7 +147,7 @@ pub fn parse_message(root: &Element) -> Result { pub fn serialise_payload(payload: &MessagePayload) -> Element { match *payload { MessagePayload::Body(ref body) => body::serialise(body), - MessagePayload::StanzaError(ref stanza_error) => stanza_error::serialise(stanza_error), + MessagePayload::StanzaError(ref stanza_error) => stanza_error.into(), MessagePayload::Attention(ref attention) => attention.into(), MessagePayload::ChatState(ref chatstate) => chatstate.into(), MessagePayload::Receipt(ref receipt) => receipt.into(), diff --git a/src/presence.rs b/src/presence.rs index 6ae97ec..4ec697c 100644 --- a/src/presence.rs +++ b/src/presence.rs @@ -16,7 +16,7 @@ use error::Error; use ns; -use stanza_error; +use stanza_error::StanzaError; use delay::Delay; use ecaps2::ECaps2; @@ -51,7 +51,7 @@ pub enum PresencePayload { Show(Show), Status(Status), Priority(Priority), - StanzaError(stanza_error::StanzaError), + StanzaError(StanzaError), Delay(Delay), ECaps2(ECaps2), } @@ -179,7 +179,7 @@ pub fn parse_presence(root: &Element) -> Result { } priority = Some(Priority::from_str(elem.text().as_ref())?); } else { - let payload = if let Ok(stanza_error) = stanza_error::parse_stanza_error(elem) { + let payload = if let Ok(stanza_error) = StanzaError::try_from(elem) { Some(PresencePayload::StanzaError(stanza_error)) } else if let Ok(delay) = Delay::try_from(elem) { Some(PresencePayload::Delay(delay)) @@ -226,7 +226,7 @@ pub fn serialise_payload(payload: &PresencePayload) -> Element { .append(format!("{}", priority)) .build() }, - PresencePayload::StanzaError(ref stanza_error) => stanza_error::serialise(stanza_error), + PresencePayload::StanzaError(ref stanza_error) => stanza_error.into(), PresencePayload::Delay(ref delay) => delay.into(), PresencePayload::ECaps2(ref ecaps2) => ecaps2.into(), } diff --git a/src/stanza_error.rs b/src/stanza_error.rs index 0a1eb42..9a0bfa0 100644 --- a/src/stanza_error.rs +++ b/src/stanza_error.rs @@ -4,6 +4,7 @@ // 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 std::convert::TryFrom; use std::str::FromStr; use std::collections::BTreeMap; @@ -149,104 +150,108 @@ pub struct StanzaError { pub other: Option, } -pub fn parse_stanza_error(root: &Element) -> Result { - if !root.is("error", ns::JABBER_CLIENT) { - return Err(Error::ParseError("This is not an error element.")); - } +impl<'a> TryFrom<&'a Element> for StanzaError { + type Error = Error; - let type_ = root.attr("type") - .ok_or(Error::ParseError("Error must have a 'type' attribute."))? - .parse()?; - let by = root.attr("by") - .and_then(|by| by.parse().ok()); - let mut defined_condition = None; - let mut texts = BTreeMap::new(); - let mut other = None; - - for child in root.children() { - if child.is("text", ns::XMPP_STANZAS) { - for _ in child.children() { - return Err(Error::ParseError("Unknown element in error text.")); - } - let lang = child.attr("xml:lang").unwrap_or("").to_owned(); - if let Some(_) = texts.insert(lang, child.text()) { - return Err(Error::ParseError("Text element present twice for the same xml:lang.")); - } - } else if child.ns() == Some(ns::XMPP_STANZAS) { - if defined_condition.is_some() { - return Err(Error::ParseError("Error must not have more than one defined-condition.")); - } - for _ in child.children() { - return Err(Error::ParseError("Unknown element in defined-condition.")); - } - let condition = DefinedCondition::from_str(child.name())?; - defined_condition = Some(condition); - } else { - if other.is_some() { - return Err(Error::ParseError("Error must not have more than one other element.")); - } - other = Some(child.clone()); + fn try_from(elem: &'a Element) -> Result { + if !elem.is("error", ns::JABBER_CLIENT) { + return Err(Error::ParseError("This is not an error element.")); } - } - if defined_condition.is_none() { - return Err(Error::ParseError("Error must have a defined-condition.")); - } - let defined_condition = defined_condition.unwrap(); + let type_ = elem.attr("type") + .ok_or(Error::ParseError("Error must have a 'type' attribute."))? + .parse()?; + let by = elem.attr("by") + .and_then(|by| by.parse().ok()); + let mut defined_condition = None; + let mut texts = BTreeMap::new(); + let mut other = None; - Ok(StanzaError { - type_: type_, - by: by, - defined_condition: defined_condition, - texts: texts, - other: other, - }) + for child in elem.children() { + if child.is("text", ns::XMPP_STANZAS) { + for _ in child.children() { + return Err(Error::ParseError("Unknown element in error text.")); + } + let lang = child.attr("xml:lang").unwrap_or("").to_owned(); + if let Some(_) = texts.insert(lang, child.text()) { + return Err(Error::ParseError("Text element present twice for the same xml:lang.")); + } + } else if child.ns() == Some(ns::XMPP_STANZAS) { + if defined_condition.is_some() { + return Err(Error::ParseError("Error must not have more than one defined-condition.")); + } + for _ in child.children() { + return Err(Error::ParseError("Unknown element in defined-condition.")); + } + let condition = DefinedCondition::from_str(child.name())?; + defined_condition = Some(condition); + } else { + if other.is_some() { + return Err(Error::ParseError("Error must not have more than one other element.")); + } + other = Some(child.clone()); + } + } + + if defined_condition.is_none() { + return Err(Error::ParseError("Error must have a defined-condition.")); + } + let defined_condition = defined_condition.unwrap(); + + Ok(StanzaError { + type_: type_, + by: by, + defined_condition: defined_condition, + texts: texts, + other: other, + }) + } } -pub fn serialise(error: &StanzaError) -> Element { - let mut root = Element::builder("error") - .ns(ns::JABBER_CLIENT) - .attr("type", String::from(error.type_.clone())) - .attr("by", match error.by { - Some(ref by) => Some(String::from(by.clone())), - None => None, - }) - .append(Element::builder(error.defined_condition.clone()) - .ns(ns::XMPP_STANZAS) - .build()) - .build(); - for (lang, text) in error.texts.clone() { - let elem = Element::builder("text") - .ns(ns::XMPP_STANZAS) - .attr("xml:lang", lang) - .append(text) - .build(); - root.append_child(elem); +impl<'a> Into for &'a StanzaError { + fn into(self) -> Element { + let mut root = Element::builder("error") + .ns(ns::JABBER_CLIENT) + .attr("type", String::from(self.type_.clone())) + .attr("by", match self.by { + Some(ref by) => Some(String::from(by.clone())), + None => None, + }) + .append(Element::builder(self.defined_condition.clone()) + .ns(ns::XMPP_STANZAS) + .build()) + .build(); + for (lang, text) in self.texts.clone() { + let elem = Element::builder("text") + .ns(ns::XMPP_STANZAS) + .attr("xml:lang", lang) + .append(text) + .build(); + root.append_child(elem); + } + if let Some(ref other) = self.other { + root.append_child(other.clone()); + } + root } - if let Some(ref other) = error.other { - root.append_child(other.clone()); - } - root } #[cfg(test)] mod tests { - use minidom::Element; - use error::Error; - use stanza_error; + use super::*; #[test] fn test_simple() { let elem: Element = "".parse().unwrap(); - let error = stanza_error::parse_stanza_error(&elem).unwrap(); - assert_eq!(error.type_, stanza_error::ErrorType::Cancel); - assert_eq!(error.defined_condition, stanza_error::DefinedCondition::UndefinedCondition); + let error = StanzaError::try_from(&elem).unwrap(); + assert_eq!(error.type_, ErrorType::Cancel); + assert_eq!(error.defined_condition, DefinedCondition::UndefinedCondition); } #[test] fn test_invalid_type() { let elem: Element = "".parse().unwrap(); - let error = stanza_error::parse_stanza_error(&elem).unwrap_err(); + let error = StanzaError::try_from(&elem).unwrap_err(); let message = match error { Error::ParseError(string) => string, _ => panic!(), @@ -254,7 +259,7 @@ mod tests { assert_eq!(message, "Error must have a 'type' attribute."); let elem: Element = "".parse().unwrap(); - let error = stanza_error::parse_stanza_error(&elem).unwrap_err(); + let error = StanzaError::try_from(&elem).unwrap_err(); let message = match error { Error::ParseError(string) => string, _ => panic!(), @@ -265,7 +270,7 @@ mod tests { #[test] fn test_invalid_condition() { let elem: Element = "".parse().unwrap(); - let error = stanza_error::parse_stanza_error(&elem).unwrap_err(); + let error = StanzaError::try_from(&elem).unwrap_err(); let message = match error { Error::ParseError(string) => string, _ => panic!(),