presence: Simplify the code.

This commit is contained in:
Emmanuel Gil Peyrot 2017-05-24 21:30:33 +01:00
parent 6f7e504c8a
commit fbeeae5c64

View file

@ -8,7 +8,7 @@ use std::convert::TryFrom;
use std::str::FromStr;
use std::collections::BTreeMap;
use minidom::{Element, IntoElements, IntoAttributeValue, ElementEmitter};
use minidom::{Element, IntoAttributeValue};
use jid::Jid;
@ -29,15 +29,31 @@ pub enum Show {
Xa,
}
impl IntoElements for Show {
fn into_elements(self, emitter: &mut ElementEmitter) {
let elem = Element::builder(match self {
Show::Away => "away",
Show::Chat => "chat",
Show::Dnd => "dnd",
Show::Xa => "xa",
}).build();
emitter.append_child(elem);
impl FromStr for Show {
type Err = Error;
fn from_str(s: &str) -> Result<Show, Error> {
Ok(match s {
"away" => Show::Away,
"chat" => Show::Chat,
"dnd" => Show::Dnd,
"xa" => Show::Xa,
_ => return Err(Error::ParseError("Invalid value for show.")),
})
}
}
impl Into<Element> for Show {
fn into(self) -> Element {
Element::builder("show")
.append(match self {
Show::Away => "away",
Show::Chat => "chat",
Show::Dnd => "dnd",
Show::Xa => "xa",
})
.build()
}
}
@ -86,7 +102,7 @@ impl Into<Element> for PresencePayload {
PresencePayload::Idle(idle) => idle.into(),
PresencePayload::ECaps2(ecaps2) => ecaps2.into(),
PresencePayload::Unknown(elem) => elem.clone(),
PresencePayload::Unknown(elem) => elem,
}
}
}
@ -164,17 +180,20 @@ impl TryFrom<Element> for Presence {
if !root.is("presence", ns::JABBER_CLIENT) {
return Err(Error::ParseError("This is not a presence element."));
}
let from = get_attr!(root, "from", optional);
let to = get_attr!(root, "to", optional);
let id = get_attr!(root, "id", optional);
let type_ = get_attr!(root, "type", default);
let mut show = None;
let mut statuses = BTreeMap::new();
let mut priority = None;
let mut payloads = vec!();
let mut presence = Presence {
from: get_attr!(root, "from", optional),
to: get_attr!(root, "to", optional),
id: get_attr!(root, "id", optional),
type_: get_attr!(root, "type", default),
show: None,
statuses: BTreeMap::new(),
priority: 0i8,
payloads: vec!(),
};
for elem in root.children() {
if elem.is("show", ns::JABBER_CLIENT) {
if show.is_some() {
if presence.show.is_some() {
return Err(Error::ParseError("More than one show element in a presence."));
}
for _ in elem.children() {
@ -183,14 +202,7 @@ impl TryFrom<Element> for Presence {
for _ in elem.attrs() {
return Err(Error::ParseError("Unknown attribute in show element."));
}
show = Some(match elem.text().as_ref() {
"away" => Show::Away,
"chat" => Show::Chat,
"dnd" => Show::Dnd,
"xa" => Show::Xa,
_ => return Err(Error::ParseError("Invalid value for show.")),
});
presence.show = Some(Show::from_str(elem.text().as_ref())?);
} else if elem.is("status", ns::JABBER_CLIENT) {
for _ in elem.children() {
return Err(Error::ParseError("Unknown child in status element."));
@ -201,7 +213,7 @@ impl TryFrom<Element> for Presence {
}
}
let lang = get_attr!(elem, "xml:lang", default);
if statuses.insert(lang, elem.text()).is_some() {
if presence.statuses.insert(lang, elem.text()).is_some() {
return Err(Error::ParseError("Status element present twice for the same xml:lang."));
}
} else if elem.is("priority", ns::JABBER_CLIENT) {
@ -216,46 +228,40 @@ impl TryFrom<Element> for Presence {
}
priority = Some(Priority::from_str(elem.text().as_ref())?);
} else {
payloads.push(elem.clone());
presence.payloads.push(elem.clone());
}
}
Ok(Presence {
from: from,
to: to,
id: id,
type_: type_,
show: show,
statuses: statuses,
priority: priority.unwrap_or(0i8),
payloads: payloads,
})
if let Some(priority) = priority {
presence.priority = priority;
}
Ok(presence)
}
}
impl Into<Element> for Presence {
fn into(self) -> Element {
let mut stanza = Element::builder("presence")
.ns(ns::JABBER_CLIENT)
.attr("from", self.from.clone().and_then(|value| Some(String::from(value))))
.attr("to", self.to.clone().and_then(|value| Some(String::from(value))))
.attr("id", self.id.clone())
.attr("type", self.type_.clone())
.append(self.show.clone())
.append(self.statuses.iter().map(|(lang, status)| {
Element::builder("status")
.attr("xml:lang", match lang.as_ref() {
"" => None,
lang => Some(lang),
})
.append(status.clone())
.build()
}).collect::<Vec<_>>())
.append(if self.priority == 0 { None } else { Some(format!("{}", self.priority)) })
.build();
for child in self.payloads.clone() {
stanza.append_child(child);
}
stanza
Element::builder("presence")
.ns(ns::JABBER_CLIENT)
.attr("from", self.from.and_then(|value| Some(String::from(value))))
.attr("to", self.to.and_then(|value| Some(String::from(value))))
.attr("id", self.id)
.attr("type", self.type_)
.append(match self.show {
Some(show) => Some({ let elem: Element = show.into(); elem }),
None => None
})
.append(self.statuses.iter().map(|(lang, status)| {
Element::builder("status")
.attr("xml:lang", match lang.as_ref() {
"" => None,
lang => Some(lang),
})
.append(status)
.build()
}).collect::<Vec<_>>())
.append(if self.priority == 0 { None } else { Some(format!("{}", self.priority)) })
.append(self.payloads)
.build()
}
}