From 3e37beffe25307a31815a2c7ea21c82f2a9d1ad8 Mon Sep 17 00:00:00 2001 From: Rust Cambridge Mob Date: Thu, 16 Nov 2017 21:00:01 +0000 Subject: [PATCH] Implement macro for elements containing children --- src/disco.rs | 62 +++++++++++++-------------------------------------- src/macros.rs | 52 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 46 deletions(-) diff --git a/src/disco.rs b/src/disco.rs index 9964cd8..b4efeee 100644 --- a/src/disco.rs +++ b/src/disco.rs @@ -201,52 +201,22 @@ Item, "item", ns::DISCO_ITEMS, [ name: Option = "name" => optional, ]); -/// Structure representing a `` element. -/// -/// It should only be used in an ``, as it can only -/// represent the result, and not a request. -#[derive(Debug, Clone)] -pub struct DiscoItemsResult { - /// Node on which we have done this discovery. - pub node: Option, - - /// List of items pointed by this entity. - pub items: Vec, -} - -impl TryFrom for DiscoItemsResult { - type Err = Error; - - fn try_from(elem: Element) -> Result { - check_self!(elem, "query", ns::DISCO_ITEMS, "disco#items query"); - check_no_unknown_attributes!(elem, "disco#items query", ["node"]); - - let mut items: Vec = vec!(); - for child in elem.children() { - if child.is("item", ns::DISCO_ITEMS) { - items.push(Item::try_from(child.clone())?); - } else { - return Err(Error::ParseError("Unknown element in disco#items.")); - } - } - - Ok(DiscoItemsResult { - node: get_attr!(elem, "node", optional), - items: items, - }) - } -} - -impl From for Element { - fn from(disco: DiscoItemsResult) -> Element { - Element::builder("query") - .ns(ns::DISCO_ITEMS) - .attr("node", disco.node) - .append(disco.items) - .build() - } -} +generate_element_with_children!( + /// Structure representing a `` element. + /// + /// It should only be used in an ``, as it can only + /// represent the result, and not a request. + DiscoItemsResult, "query", ns::DISCO_ITEMS, + attributes: [ + /// Node on which we have done this discovery. + node: Option = "node" => optional + ], + children: [ + /// List of items pointed by this entity. + items: Vec = "item" => Item + ] +); #[cfg(test)] mod tests { diff --git a/src/macros.rs b/src/macros.rs index 155767a..136b32f 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -293,3 +293,55 @@ macro_rules! generate_element_with_text { } ); } + +macro_rules! generate_element_with_children { + ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:expr, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),+], children: [$($(#[$child_meta:meta])* $child_ident:ident: Vec<$child_type:ty> = $child_name:tt => $child_constructor:ident),+]) => ( + $(#[$meta])* + #[derive(Debug, Clone)] + pub struct $elem { + $( + $(#[$attr_meta])* + pub $attr: $attr_type + ),*, + $( + $(#[$child_meta])* + pub $child_ident: Vec<$child_type> + ),* + } + + impl TryFrom for $elem { + type Err = Error; + + fn try_from(elem: Element) -> Result<$elem, Error> { + check_self!(elem, $name, $ns); + check_no_unknown_attributes!(elem, $name, [$($attr_name),*]); + let mut parsed_children = vec!(); + for child in elem.children() { + $( + let parsed_child = $child_constructor::try_from(child.clone())?; + parsed_children.push(parsed_child); + )* + } + Ok($elem { + $( + $attr: get_attr!(elem, $attr_name, $attr_action) + ),*, + $( + $child_ident: parsed_children + )* + }) + } + } + + impl From<$elem> for Element { + fn from(elem: $elem) -> Element { + Element::builder($name) + .ns($ns) + $( + .attr($attr_name, elem.$attr) + )* + .build() + } + } + ); +}