roster: Simplify parsing of Item.

This commit is contained in:
Emmanuel Gil Peyrot 2017-11-24 05:09:25 +00:00
parent 80a2f425e2
commit 42a3e42533
2 changed files with 35 additions and 56 deletions

View file

@ -8,6 +8,13 @@ macro_rules! get_attr {
($elem:ident, $attr:tt, $type:tt) => ( ($elem:ident, $attr:tt, $type:tt) => (
get_attr!($elem, $attr, $type, value, value.parse()?) get_attr!($elem, $attr, $type, value, value.parse()?)
); );
($elem:ident, $attr:tt, optional_empty, $value:ident, $func:expr) => (
match $elem.attr($attr) {
Some("") => None,
Some($value) => Some($func),
None => None,
}
);
($elem:ident, $attr:tt, optional, $value:ident, $func:expr) => ( ($elem:ident, $attr:tt, optional, $value:ident, $func:expr) => (
match $elem.attr($attr) { match $elem.attr($attr) {
Some($value) => Some($func), Some($value) => Some($func),
@ -277,6 +284,16 @@ macro_rules! generate_elem_id {
Ok($elem(String::from(s))) Ok($elem(String::from(s)))
} }
} }
impl TryFrom<Element> for $elem {
type Err = Error;
fn try_from(elem: Element) -> Result<$elem, Error> {
check_self!(elem, $name, $ns);
check_no_children!(elem, $name);
check_no_attributes!(elem, $name);
// TODO: add a way to parse that differently when needed.
Ok($elem(elem.text()))
}
}
impl From<$elem> for Element { impl From<$elem> for Element {
fn from(elem: $elem) -> Element { fn from(elem: $elem) -> Element {
Element::builder($name) Element::builder($name)

View file

@ -23,64 +23,26 @@ generate_attribute!(Subscription, "subscription", {
Remove => "remove", Remove => "remove",
}, Default = None); }, Default = None);
/// Contact from the users contact list. generate_element_with_children!(
#[derive(Debug, Clone, PartialEq)] /// Contact from the users contact list.
pub struct Item { #[derive(PartialEq)]
/// JID of this contact. Item, "item", ns::ROSTER,
pub jid: Jid, attributes: [
/// JID of this contact.
jid: Jid = "jid" => required,
/// Name of this contact. /// Name of this contact.
pub name: Option<String>, name: Option<String> = "name" => optional_empty,
/// Subscription status of this contact. /// Subscription status of this contact.
pub subscription: Subscription, subscription: Subscription = "subscription" => default
],
/// Groups this contact is part of. children: [
pub groups: Vec<Group>, /// Groups this contact is part of.
} groups: Vec<Group> = ("group", ns::ROSTER) => Group
]
impl TryFrom<Element> for Item { );
type Err = Error;
fn try_from(elem: Element) -> Result<Item, Error> {
if !elem.is("item", ns::ROSTER) {
return Err(Error::ParseError("This is not a roster item element."));
}
let mut item = Item {
jid: get_attr!(elem, "jid", required),
name: get_attr!(elem, "name", optional).and_then(|name| if name == "" { None } else { Some(name) }),
subscription: get_attr!(elem, "subscription", default),
groups: vec!(),
};
for child in elem.children() {
if !child.is("group", ns::ROSTER) {
return Err(Error::ParseError("Unknown element in roster item element."));
}
for _ in child.children() {
return Err(Error::ParseError("Roster item group cant have children."));
}
for _ in child.attrs() {
return Err(Error::ParseError("Roster item group cant have attributes."));
}
let group = Group(child.text());
item.groups.push(group);
}
Ok(item)
}
}
impl From<Item> for Element {
fn from(item: Item) -> Element {
Element::builder("item")
.ns(ns::ROSTER)
.attr("jid", item.jid)
.attr("name", item.name)
.attr("subscription", item.subscription)
.append(item.groups)
.build()
}
}
generate_element_with_children!( generate_element_with_children!(
/// The contact list of the user. /// The contact list of the user.
@ -258,6 +220,6 @@ mod tests {
Error::ParseError(string) => string, Error::ParseError(string) => string,
_ => panic!(), _ => panic!(),
}; };
assert_eq!(message, "Unknown element in roster item element."); assert_eq!(message, "Unknown child in item element.");
} }
} }