macros: Merge all element children into a common syntax.
This commit is contained in:
parent
cbef3f6e8d
commit
a625b88fce
8 changed files with 200 additions and 490 deletions
211
src/macros.rs
211
src/macros.rs
|
|
@ -424,14 +424,96 @@ macro_rules! generate_element_with_text {
|
|||
);
|
||||
}
|
||||
|
||||
macro_rules! start_decl {
|
||||
(Vec, $type:ty) => (
|
||||
Vec<$type>
|
||||
);
|
||||
(Option, $type:ty) => (
|
||||
Option<$type>
|
||||
);
|
||||
(Required, $type:ty) => (
|
||||
$type
|
||||
);
|
||||
}
|
||||
|
||||
macro_rules! start_parse_elem {
|
||||
($temp:ident: Vec) => (
|
||||
let mut $temp = Vec::new();
|
||||
);
|
||||
($temp:ident: Option) => (
|
||||
let mut $temp = None;
|
||||
);
|
||||
($temp:ident: Required) => (
|
||||
let mut $temp = None;
|
||||
);
|
||||
}
|
||||
|
||||
macro_rules! do_parse {
|
||||
($elem:ident, Element) => (
|
||||
$elem.clone()
|
||||
);
|
||||
($elem:ident, String) => (
|
||||
$elem.text()
|
||||
);
|
||||
($elem:ident, $constructor:ident) => (
|
||||
$constructor::try_from($elem.clone())?
|
||||
);
|
||||
}
|
||||
|
||||
macro_rules! do_parse_elem {
|
||||
($temp:ident: Vec = $constructor:ident => $elem:ident) => (
|
||||
$temp.push(do_parse!($elem, $constructor));
|
||||
);
|
||||
($temp:ident: Option = $constructor:ident => $elem:ident) => (
|
||||
if $temp.is_some() {
|
||||
return Err(::error::Error::ParseError(concat!("coucou", " must not have more than one ", "coucou", ".")));
|
||||
}
|
||||
$temp = Some(do_parse!($elem, $constructor));
|
||||
);
|
||||
($temp:ident: Required = $constructor:ident => $elem:ident) => (
|
||||
$temp = Some(do_parse!($elem, $constructor));
|
||||
);
|
||||
}
|
||||
|
||||
macro_rules! finish_parse_elem {
|
||||
($temp:ident: Vec = $name:tt) => (
|
||||
$temp
|
||||
);
|
||||
($temp:ident: Option = $name:tt) => (
|
||||
$temp
|
||||
);
|
||||
($temp:ident: Required = $name:tt) => (
|
||||
$temp.ok_or(::error::Error::ParseError(concat!("Missing child coucou in ", $name, " element.")))?
|
||||
);
|
||||
}
|
||||
|
||||
macro_rules! generate_serialiser {
|
||||
($parent:ident, $elem:ident, Required, String, ($name:tt, $ns:ident)) => (
|
||||
::minidom::Element::builder($name)
|
||||
.ns(::ns::$ns)
|
||||
.append($parent.$elem)
|
||||
.build()
|
||||
);
|
||||
($parent:ident, $elem:ident, Option, String, ($name:tt, $ns:ident)) => (
|
||||
$parent.$elem.map(|elem|
|
||||
::minidom::Element::builder($name)
|
||||
.ns(::ns::$ns)
|
||||
.append(elem)
|
||||
.build())
|
||||
);
|
||||
($parent:ident, $elem:ident, $_:ident, $constructor:ident, ($name:tt, $ns:ident)) => (
|
||||
$parent.$elem
|
||||
);
|
||||
}
|
||||
|
||||
macro_rules! generate_element_with_children {
|
||||
($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, children: [$($(#[$child_meta:meta])* $child_ident:ident: Vec<$child_type:ty> = ($child_name:tt, $child_ns:ident) => $child_constructor:ident),+]) => (
|
||||
generate_element_with_children!($(#[$meta])* $elem, $name, $ns, attributes: [], children: [$($(#[$child_meta])* $child_ident: Vec<$child_type> = ($child_name, $child_ns) => $child_constructor),+]);
|
||||
($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, children: [$($(#[$child_meta:meta])* $child_ident:ident: $coucou:tt<$child_type:ty> = ($child_name:tt, $child_ns:ident) => $child_constructor:ident),+]) => (
|
||||
generate_element_with_children!($(#[$meta])* $elem, $name, $ns, attributes: [], children: [$($(#[$child_meta])* $child_ident: $coucou<$child_type> = ($child_name, $child_ns) => $child_constructor),+]);
|
||||
);
|
||||
($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, 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_ns:ident) => $child_constructor:ident),+]) => (
|
||||
generate_element_with_children!($(#[$meta])* $elem, $name, $ns, attributes: [$($(#[$attr_meta])* $attr: $attr_type = $attr_name => $attr_action),*], children: [$($(#[$child_meta])* $child_ident: Vec<$child_type> = ($child_name, $child_ns) => $child_constructor),+]);
|
||||
($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),*,], children: [$($(#[$child_meta:meta])* $child_ident:ident: $coucou:tt<$child_type:ty> = ($child_name:tt, $child_ns:ident) => $child_constructor:ident),+]) => (
|
||||
generate_element_with_children!($(#[$meta])* $elem, $name, $ns, attributes: [$($(#[$attr_meta])* $attr: $attr_type = $attr_name => $attr_action),*], children: [$($(#[$child_meta])* $child_ident: $coucou<$child_type> = ($child_name, $child_ns) => $child_constructor),+]);
|
||||
);
|
||||
($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, 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_ns:ident) => $child_constructor:ident),+]) => (
|
||||
($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),*], children: [$($(#[$child_meta:meta])* $child_ident:ident: $coucou:tt<$child_type:ty> = ($child_name:tt, $child_ns:ident) => $child_constructor:ident),+]) => (
|
||||
$(#[$meta])*
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct $elem {
|
||||
|
|
@ -441,7 +523,7 @@ macro_rules! generate_element_with_children {
|
|||
)*
|
||||
$(
|
||||
$(#[$child_meta])*
|
||||
pub $child_ident: Vec<$child_type>,
|
||||
pub $child_ident: start_decl!($coucou, $child_type),
|
||||
)*
|
||||
}
|
||||
|
||||
|
|
@ -451,12 +533,13 @@ macro_rules! generate_element_with_children {
|
|||
fn try_from(elem: ::minidom::Element) -> Result<$elem, ::error::Error> {
|
||||
check_self!(elem, $name, $ns);
|
||||
check_no_unknown_attributes!(elem, $name, [$($attr_name),*]);
|
||||
let mut parsed_children = vec!();
|
||||
$(
|
||||
start_parse_elem!($child_ident: $coucou);
|
||||
)*
|
||||
for child in elem.children() {
|
||||
$(
|
||||
if child.is($child_name, ::ns::$child_ns) {
|
||||
let parsed_child = $child_constructor::try_from(child.clone())?;
|
||||
parsed_children.push(parsed_child);
|
||||
do_parse_elem!($child_ident: $coucou = $child_constructor => child);
|
||||
continue;
|
||||
}
|
||||
)*
|
||||
|
|
@ -467,7 +550,7 @@ macro_rules! generate_element_with_children {
|
|||
$attr: get_attr!(elem, $attr_name, $attr_action),
|
||||
)*
|
||||
$(
|
||||
$child_ident: parsed_children,
|
||||
$child_ident: finish_parse_elem!($child_ident: $coucou = $child_name),
|
||||
)*
|
||||
})
|
||||
}
|
||||
|
|
@ -481,116 +564,10 @@ macro_rules! generate_element_with_children {
|
|||
.attr($attr_name, elem.$attr)
|
||||
)*
|
||||
$(
|
||||
.append(elem.$child_ident)
|
||||
.append(generate_serialiser!(elem, $child_ident, $coucou, $child_constructor, ($child_name, $child_ns)))
|
||||
)*
|
||||
.build()
|
||||
}
|
||||
}
|
||||
);
|
||||
($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, child: ($(#[$child_meta:meta])* $child_ident:ident: Option<$child_type:ty> = ($child_name:tt, $child_ns:ident) => $child_constructor:ident)) => (
|
||||
generate_element_with_children!($(#[$meta])* $elem, $name, $ns, attributes: [], child: ($(#[$child_meta])* $child_ident: Option<$child_type> = ($child_name, $child_ns) => $child_constructor));
|
||||
);
|
||||
($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),*,], child: ($(#[$child_meta:meta])* $child_ident:ident: Option<$child_type:ty> = ($child_name:tt, $child_ns:ident) => $child_constructor:ident)) => (
|
||||
generate_element_with_children!($(#[$meta])* $elem, $name, $ns, attributes: [$($(#[$attr_meta])* $attr: $attr_type = $attr_name => $attr_action),*], child: ($(#[$child_meta])* $child_ident: Option<$child_type> = ($child_name, $child_ns) => $child_constructor));
|
||||
);
|
||||
($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),*], child: ($(#[$child_meta:meta])* $child_ident:ident: Option<$child_type:ty> = ($child_name:tt, $child_ns:ident) => $child_constructor:ident)) => (
|
||||
$(#[$meta])*
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct $elem {
|
||||
$(
|
||||
$(#[$attr_meta])*
|
||||
pub $attr: $attr_type,
|
||||
)*
|
||||
$(#[$child_meta])*
|
||||
pub $child_ident: Option<$child_type>,
|
||||
}
|
||||
|
||||
impl ::try_from::TryFrom<::minidom::Element> for $elem {
|
||||
type Err = ::error::Error;
|
||||
|
||||
fn try_from(elem: ::minidom::Element) -> Result<$elem, ::error::Error> {
|
||||
check_self!(elem, $name, $ns);
|
||||
check_no_unknown_attributes!(elem, $name, [$($attr_name),*]);
|
||||
let mut parsed_child = None;
|
||||
for child in elem.children() {
|
||||
if child.is($child_name, ::ns::$child_ns) {
|
||||
parsed_child = Some($child_constructor::try_from(child.clone())?);
|
||||
continue;
|
||||
}
|
||||
return Err(::error::Error::ParseError(concat!("Unknown child in ", $name, " element.")));
|
||||
}
|
||||
Ok($elem {
|
||||
$(
|
||||
$attr: get_attr!(elem, $attr_name, $attr_action),
|
||||
)*
|
||||
$child_ident: parsed_child,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$elem> for ::minidom::Element {
|
||||
fn from(elem: $elem) -> ::minidom::Element {
|
||||
::minidom::Element::builder($name)
|
||||
.ns(::ns::$ns)
|
||||
$(
|
||||
.attr($attr_name, elem.$attr)
|
||||
)*
|
||||
.append(elem.$child_ident)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
);
|
||||
($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, child: ($(#[$child_meta:meta])* $child_ident:ident: $child_type:ty = ($child_name:tt, $child_ns:ident) => $child_constructor:ident)) => (
|
||||
generate_element_with_children!($(#[$meta])* $elem, $name, $ns, attributes: [], child: ($(#[$child_meta])* $child_ident: $child_type = ($child_name, $child_ns) => $child_constructor));
|
||||
);
|
||||
($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),*,], child: ($(#[$child_meta:meta])* $child_ident:ident: $child_type:ty = ($child_name:tt, $child_ns:ident) => $child_constructor:ident)) => (
|
||||
generate_element_with_children!($(#[$meta])* $elem, $name, $ns, attributes: [$($(#[$attr_meta])* $attr: $attr_type = $attr_name => $attr_action),*], child: ($(#[$child_meta])* $child_ident: $child_type = ($child_name, $child_ns) => $child_constructor));
|
||||
);
|
||||
($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),*], child: ($(#[$child_meta:meta])* $child_ident:ident: $child_type:ty = ($child_name:tt, $child_ns:ident) => $child_constructor:ident)) => (
|
||||
$(#[$meta])*
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct $elem {
|
||||
$(
|
||||
$(#[$attr_meta])*
|
||||
pub $attr: $attr_type,
|
||||
)*
|
||||
$(#[$child_meta])*
|
||||
pub $child_ident: $child_type,
|
||||
}
|
||||
|
||||
impl ::try_from::TryFrom<::minidom::Element> for $elem {
|
||||
type Err = ::error::Error;
|
||||
|
||||
fn try_from(elem: ::minidom::Element) -> Result<$elem, ::error::Error> {
|
||||
check_self!(elem, $name, $ns);
|
||||
check_no_unknown_attributes!(elem, $name, [$($attr_name),*]);
|
||||
let mut parsed_child = None;
|
||||
for child in elem.children() {
|
||||
if child.is($child_name, ::ns::$child_ns) {
|
||||
parsed_child = Some($child_constructor::try_from(child.clone())?);
|
||||
continue;
|
||||
}
|
||||
return Err(::error::Error::ParseError(concat!("Unknown child in ", $name, " element.")));
|
||||
}
|
||||
Ok($elem {
|
||||
$(
|
||||
$attr: get_attr!(elem, $attr_name, $attr_action),
|
||||
)*
|
||||
$child_ident: parsed_child.ok_or(::error::Error::ParseError(concat!("Missing child ", $child_name, " in ", $name, " element.")))?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$elem> for ::minidom::Element {
|
||||
fn from(elem: $elem) -> ::minidom::Element {
|
||||
::minidom::Element::builder($name)
|
||||
.ns(::ns::$ns)
|
||||
$(
|
||||
.attr($attr_name, elem.$attr)
|
||||
)*
|
||||
.append(elem.$child_ident)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue