diff --git a/src/macros.rs b/src/macros.rs index 1569470..b084207 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -8,6 +8,13 @@ macro_rules! get_attr { ($elem:ident, $attr:tt, $type:tt) => ( 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) => ( match $elem.attr($attr) { Some($value) => Some($func), @@ -277,6 +284,16 @@ macro_rules! generate_elem_id { Ok($elem(String::from(s))) } } + impl TryFrom 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 { fn from(elem: $elem) -> Element { Element::builder($name) diff --git a/src/roster.rs b/src/roster.rs index cb57ed3..cb78e4e 100644 --- a/src/roster.rs +++ b/src/roster.rs @@ -23,64 +23,26 @@ generate_attribute!(Subscription, "subscription", { Remove => "remove", }, Default = None); -/// Contact from the user’s contact list. -#[derive(Debug, Clone, PartialEq)] -pub struct Item { - /// JID of this contact. - pub jid: Jid, +generate_element_with_children!( + /// Contact from the user’s contact list. + #[derive(PartialEq)] + Item, "item", ns::ROSTER, + attributes: [ + /// JID of this contact. + jid: Jid = "jid" => required, - /// Name of this contact. - pub name: Option, + /// Name of this contact. + name: Option = "name" => optional_empty, - /// Subscription status of this contact. - pub subscription: Subscription, + /// Subscription status of this contact. + subscription: Subscription = "subscription" => default + ], - /// Groups this contact is part of. - pub groups: Vec, -} - -impl TryFrom for Item { - type Err = Error; - - fn try_from(elem: Element) -> Result { - 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 can’t have children.")); - } - for _ in child.attrs() { - return Err(Error::ParseError("Roster item group can’t have attributes.")); - } - let group = Group(child.text()); - item.groups.push(group); - } - Ok(item) - } -} - -impl From 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() - } -} + children: [ + /// Groups this contact is part of. + groups: Vec = ("group", ns::ROSTER) => Group + ] +); generate_element_with_children!( /// The contact list of the user. @@ -258,6 +220,6 @@ mod tests { Error::ParseError(string) => string, _ => panic!(), }; - assert_eq!(message, "Unknown element in roster item element."); + assert_eq!(message, "Unknown child in item element."); } }