From bd9aa01ad54c9a320fc84fd3cba1329304be8e9c Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Tue, 31 Oct 2017 21:17:24 +0000 Subject: [PATCH] Split macros into their own module. --- src/lib.rs | 251 +------------------------------------------------ src/macros.rs | 253 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 256 insertions(+), 248 deletions(-) create mode 100644 src/macros.rs diff --git a/src/lib.rs b/src/lib.rs index db57ce2698cc459f1d381889d6672d749bff18c0..4a40ae119f69218f7f0f7a3a20a677c5377eac71 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,258 +33,13 @@ extern crate blake2; extern crate chrono; extern crate try_from; -macro_rules! get_attr { - ($elem:ident, $attr:tt, $type:tt) => ( - get_attr!($elem, $attr, $type, value, value.parse()?) - ); - ($elem:ident, $attr:tt, optional, $value:ident, $func:expr) => ( - match $elem.attr($attr) { - Some($value) => Some($func), - None => None, - } - ); - ($elem:ident, $attr:tt, required, $value:ident, $func:expr) => ( - match $elem.attr($attr) { - Some($value) => $func, - None => return Err(Error::ParseError(concat!("Required attribute '", $attr, "' missing."))), - } - ); - ($elem:ident, $attr:tt, default, $value:ident, $func:expr) => ( - match $elem.attr($attr) { - Some($value) => $func, - None => Default::default(), - } - ); -} - -macro_rules! generate_attribute { - ($elem:ident, $name:tt, {$($a:ident => $b:tt),+,}) => ( - generate_attribute!($elem, $name, {$($a => $b),+}); - ); - ($elem:ident, $name:tt, {$($a:ident => $b:tt),+,}, Default = $default:ident) => ( - generate_attribute!($elem, $name, {$($a => $b),+}, Default = $default); - ); - ($elem:ident, $name:tt, {$($a:ident => $b:tt),+}) => ( - #[derive(Debug, Clone, PartialEq)] - pub enum $elem { - $( - #[doc=$b] - #[doc="value for this attribute."] - $a - ),+ - } - impl FromStr for $elem { - type Err = Error; - fn from_str(s: &str) -> Result<$elem, Error> { - Ok(match s { - $($b => $elem::$a),+, - _ => return Err(Error::ParseError(concat!("Unknown value for '", $name, "' attribute."))), - }) - } - } - impl IntoAttributeValue for $elem { - fn into_attribute_value(self) -> Option { - Some(String::from(match self { - $($elem::$a => $b),+ - })) - } - } - ); - ($elem:ident, $name:tt, {$($a:ident => $b:tt),+}, Default = $default:ident) => ( - #[derive(Debug, Clone, PartialEq)] - pub enum $elem { - $( - #[doc=$b] - #[doc="value for this attribute."] - $a - ),+ - } - impl FromStr for $elem { - type Err = Error; - fn from_str(s: &str) -> Result<$elem, Error> { - Ok(match s { - $($b => $elem::$a),+, - _ => return Err(Error::ParseError(concat!("Unknown value for '", $name, "' attribute."))), - }) - } - } - impl IntoAttributeValue for $elem { - #[allow(unreachable_patterns)] - fn into_attribute_value(self) -> Option { - Some(String::from(match self { - $elem::$default => return None, - $($elem::$a => $b),+ - })) - } - } - impl Default for $elem { - fn default() -> $elem { - $elem::$default - } - } - ); -} - -macro_rules! check_self { - ($elem:ident, $name:tt, $ns:expr) => ( - check_self!($elem, $name, $ns, $name); - ); - ($elem:ident, $name:tt, $ns:expr, $pretty_name:tt) => ( - if !$elem.is($name, $ns) { - return Err(Error::ParseError(concat!("This is not a ", $pretty_name, " element."))); - } - ); -} - -macro_rules! check_ns_only { - ($elem:ident, $name:tt, $ns:expr) => ( - if !$elem.has_ns($ns) { - return Err(Error::ParseError(concat!("This is not a ", $name, " element."))); - } - ); -} - -macro_rules! check_no_children { - ($elem:ident, $name:tt) => ( - for _ in $elem.children() { - return Err(Error::ParseError(concat!("Unknown child in ", $name, " element."))); - } - ); -} - -macro_rules! check_no_attributes { - ($elem:ident, $name:tt) => ( - check_no_unknown_attributes!($elem, $name, []); - ); -} - -macro_rules! check_no_unknown_attributes { - ($elem:ident, $name:tt, [$($attr:tt),*]) => ( - for (_attr, _) in $elem.attrs() { - $( - if _attr == $attr { - continue; - } - )* - return Err(Error::ParseError(concat!("Unknown attribute in ", $name, " element."))); - } - ); -} - -macro_rules! generate_empty_element { - ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:expr) => ( - $(#[$meta])* - #[derive(Debug, Clone)] - pub struct $elem; - - 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); - Ok($elem) - } - } - - impl From<$elem> for Element { - fn from(_: $elem) -> Element { - Element::builder($name) - .ns($ns) - .build() - } - } - ); -} - -macro_rules! generate_element_with_only_attributes { - ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:expr, [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),+,]) => ( - generate_element_with_only_attributes!($(#[$meta])* $elem, $name, $ns, [$($(#[$attr_meta])* $attr: $attr_type = $attr_name => $attr_action),*]); - ); - ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:expr, [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),+]) => ( - $(#[$meta])* - #[derive(Debug, Clone)] - pub struct $elem { - $( - $(#[$attr_meta])* - pub $attr: $attr_type - ),* - } - - 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_unknown_attributes!(elem, $name, [$($attr_name),*]); - Ok($elem { - $( - $attr: get_attr!(elem, $attr_name, $attr_action) - ),* - }) - } - } - - impl From<$elem> for Element { - fn from(elem: $elem) -> Element { - Element::builder($name) - .ns($ns) - $( - .attr($attr_name, elem.$attr) - )* - .build() - } - } - ); -} - -macro_rules! generate_id { - ($elem:ident) => ( - #[derive(Debug, Clone, PartialEq, Eq, Hash)] - pub struct $elem(pub String); - impl FromStr for $elem { - type Err = Error; - fn from_str(s: &str) -> Result<$elem, Error> { - // TODO: add a way to parse that differently when needed. - Ok($elem(String::from(s))) - } - } - impl IntoAttributeValue for $elem { - fn into_attribute_value(self) -> Option { - Some(self.0) - } - } - ); -} - -macro_rules! generate_elem_id { - ($elem:ident, $name:tt, $ns:expr) => ( - #[derive(Debug, Clone, PartialEq, Eq, Hash)] - pub struct $elem(pub String); - impl FromStr for $elem { - type Err = Error; - fn from_str(s: &str) -> Result<$elem, Error> { - // TODO: add a way to parse that differently when needed. - Ok($elem(String::from(s))) - } - } - impl From<$elem> for Element { - fn from(elem: $elem) -> Element { - Element::builder($name) - .ns($ns) - .append(elem.0) - .build() - } - } - ); -} - /// Error type returned by every parser on failure. pub mod error; /// XML namespace definitions used through XMPP. pub mod ns; +/// Helper macros to parse and serialise more easily. +#[macro_use] +pub mod macros; #[cfg(test)] /// Namespace-aware comparison for tests diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 0000000000000000000000000000000000000000..97f0adcdc684aa774aac7dedd433e739d766d40f --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,253 @@ +// Copyright (c) 2017 Emmanuel Gil Peyrot +// +// This Source Code Form is subject to the terms of the Mozilla Public +// 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/. + +macro_rules! get_attr { + ($elem:ident, $attr:tt, $type:tt) => ( + get_attr!($elem, $attr, $type, value, value.parse()?) + ); + ($elem:ident, $attr:tt, optional, $value:ident, $func:expr) => ( + match $elem.attr($attr) { + Some($value) => Some($func), + None => None, + } + ); + ($elem:ident, $attr:tt, required, $value:ident, $func:expr) => ( + match $elem.attr($attr) { + Some($value) => $func, + None => return Err(Error::ParseError(concat!("Required attribute '", $attr, "' missing."))), + } + ); + ($elem:ident, $attr:tt, default, $value:ident, $func:expr) => ( + match $elem.attr($attr) { + Some($value) => $func, + None => Default::default(), + } + ); +} + +macro_rules! generate_attribute { + ($elem:ident, $name:tt, {$($a:ident => $b:tt),+,}) => ( + generate_attribute!($elem, $name, {$($a => $b),+}); + ); + ($elem:ident, $name:tt, {$($a:ident => $b:tt),+,}, Default = $default:ident) => ( + generate_attribute!($elem, $name, {$($a => $b),+}, Default = $default); + ); + ($elem:ident, $name:tt, {$($a:ident => $b:tt),+}) => ( + #[derive(Debug, Clone, PartialEq)] + pub enum $elem { + $( + #[doc=$b] + #[doc="value for this attribute."] + $a + ),+ + } + impl FromStr for $elem { + type Err = Error; + fn from_str(s: &str) -> Result<$elem, Error> { + Ok(match s { + $($b => $elem::$a),+, + _ => return Err(Error::ParseError(concat!("Unknown value for '", $name, "' attribute."))), + }) + } + } + impl IntoAttributeValue for $elem { + fn into_attribute_value(self) -> Option { + Some(String::from(match self { + $($elem::$a => $b),+ + })) + } + } + ); + ($elem:ident, $name:tt, {$($a:ident => $b:tt),+}, Default = $default:ident) => ( + #[derive(Debug, Clone, PartialEq)] + pub enum $elem { + $( + #[doc=$b] + #[doc="value for this attribute."] + $a + ),+ + } + impl FromStr for $elem { + type Err = Error; + fn from_str(s: &str) -> Result<$elem, Error> { + Ok(match s { + $($b => $elem::$a),+, + _ => return Err(Error::ParseError(concat!("Unknown value for '", $name, "' attribute."))), + }) + } + } + impl IntoAttributeValue for $elem { + #[allow(unreachable_patterns)] + fn into_attribute_value(self) -> Option { + Some(String::from(match self { + $elem::$default => return None, + $($elem::$a => $b),+ + })) + } + } + impl Default for $elem { + fn default() -> $elem { + $elem::$default + } + } + ); +} + +macro_rules! check_self { + ($elem:ident, $name:tt, $ns:expr) => ( + check_self!($elem, $name, $ns, $name); + ); + ($elem:ident, $name:tt, $ns:expr, $pretty_name:tt) => ( + if !$elem.is($name, $ns) { + return Err(Error::ParseError(concat!("This is not a ", $pretty_name, " element."))); + } + ); +} + +macro_rules! check_ns_only { + ($elem:ident, $name:tt, $ns:expr) => ( + if !$elem.has_ns($ns) { + return Err(Error::ParseError(concat!("This is not a ", $name, " element."))); + } + ); +} + +macro_rules! check_no_children { + ($elem:ident, $name:tt) => ( + for _ in $elem.children() { + return Err(Error::ParseError(concat!("Unknown child in ", $name, " element."))); + } + ); +} + +macro_rules! check_no_attributes { + ($elem:ident, $name:tt) => ( + check_no_unknown_attributes!($elem, $name, []); + ); +} + +macro_rules! check_no_unknown_attributes { + ($elem:ident, $name:tt, [$($attr:tt),*]) => ( + for (_attr, _) in $elem.attrs() { + $( + if _attr == $attr { + continue; + } + )* + return Err(Error::ParseError(concat!("Unknown attribute in ", $name, " element."))); + } + ); +} + +macro_rules! generate_empty_element { + ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:expr) => ( + $(#[$meta])* + #[derive(Debug, Clone)] + pub struct $elem; + + 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); + Ok($elem) + } + } + + impl From<$elem> for Element { + fn from(_: $elem) -> Element { + Element::builder($name) + .ns($ns) + .build() + } + } + ); +} + +macro_rules! generate_element_with_only_attributes { + ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:expr, [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),+,]) => ( + generate_element_with_only_attributes!($(#[$meta])* $elem, $name, $ns, [$($(#[$attr_meta])* $attr: $attr_type = $attr_name => $attr_action),*]); + ); + ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:expr, [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),+]) => ( + $(#[$meta])* + #[derive(Debug, Clone)] + pub struct $elem { + $( + $(#[$attr_meta])* + pub $attr: $attr_type + ),* + } + + 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_unknown_attributes!(elem, $name, [$($attr_name),*]); + Ok($elem { + $( + $attr: get_attr!(elem, $attr_name, $attr_action) + ),* + }) + } + } + + impl From<$elem> for Element { + fn from(elem: $elem) -> Element { + Element::builder($name) + .ns($ns) + $( + .attr($attr_name, elem.$attr) + )* + .build() + } + } + ); +} + +macro_rules! generate_id { + ($elem:ident) => ( + #[derive(Debug, Clone, PartialEq, Eq, Hash)] + pub struct $elem(pub String); + impl FromStr for $elem { + type Err = Error; + fn from_str(s: &str) -> Result<$elem, Error> { + // TODO: add a way to parse that differently when needed. + Ok($elem(String::from(s))) + } + } + impl IntoAttributeValue for $elem { + fn into_attribute_value(self) -> Option { + Some(self.0) + } + } + ); +} + +macro_rules! generate_elem_id { + ($elem:ident, $name:tt, $ns:expr) => ( + #[derive(Debug, Clone, PartialEq, Eq, Hash)] + pub struct $elem(pub String); + impl FromStr for $elem { + type Err = Error; + fn from_str(s: &str) -> Result<$elem, Error> { + // TODO: add a way to parse that differently when needed. + Ok($elem(String::from(s))) + } + } + impl From<$elem> for Element { + fn from(elem: $elem) -> Element { + Element::builder($name) + .ns($ns) + .append(elem.0) + .build() + } + } + ); +}