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
|
|
@ -66,16 +66,20 @@ generate_attribute!(Disposition, "disposition", {
|
||||||
|
|
||||||
generate_id!(ContentId);
|
generate_id!(ContentId);
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
generate_element_with_children!(
|
||||||
pub struct Content {
|
Content, "content", JINGLE,
|
||||||
pub creator: Creator,
|
attributes: [
|
||||||
pub disposition: Disposition,
|
creator: Creator = "creator" => required,
|
||||||
pub name: ContentId,
|
disposition: Disposition = "disposition" => default,
|
||||||
pub senders: Senders,
|
name: ContentId = "name" => required,
|
||||||
pub description: Option<Element>,
|
senders: Senders = "senders" => default
|
||||||
pub transport: Option<Element>,
|
],
|
||||||
pub security: Option<Element>,
|
children: [
|
||||||
}
|
description: Option<Element> = ("description", JINGLE) => Element,
|
||||||
|
transport: Option<Element> = ("transport", JINGLE) => Element,
|
||||||
|
security: Option<Element> = ("security", JINGLE) => Element
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
impl Content {
|
impl Content {
|
||||||
pub fn new(creator: Creator, name: ContentId) -> Content {
|
pub fn new(creator: Creator, name: ContentId) -> Content {
|
||||||
|
|
@ -116,61 +120,6 @@ impl Content {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<Element> for Content {
|
|
||||||
type Err = Error;
|
|
||||||
|
|
||||||
fn try_from(elem: Element) -> Result<Content, Error> {
|
|
||||||
check_self!(elem, "content", JINGLE);
|
|
||||||
check_no_unknown_attributes!(elem, "content", ["creator", "disposition", "name", "senders"]);
|
|
||||||
|
|
||||||
let mut content = Content {
|
|
||||||
creator: get_attr!(elem, "creator", required),
|
|
||||||
disposition: get_attr!(elem, "disposition", default),
|
|
||||||
name: get_attr!(elem, "name", required),
|
|
||||||
senders: get_attr!(elem, "senders", default),
|
|
||||||
description: None,
|
|
||||||
transport: None,
|
|
||||||
security: None,
|
|
||||||
};
|
|
||||||
for child in elem.children() {
|
|
||||||
if child.name() == "description" {
|
|
||||||
if content.description.is_some() {
|
|
||||||
return Err(Error::ParseError("Content must not have more than one description."));
|
|
||||||
}
|
|
||||||
content.description = Some(child.clone());
|
|
||||||
} else if child.name() == "transport" {
|
|
||||||
if content.transport.is_some() {
|
|
||||||
return Err(Error::ParseError("Content must not have more than one transport."));
|
|
||||||
}
|
|
||||||
content.transport = Some(child.clone());
|
|
||||||
} else if child.name() == "security" {
|
|
||||||
if content.security.is_some() {
|
|
||||||
return Err(Error::ParseError("Content must not have more than one security."));
|
|
||||||
}
|
|
||||||
content.security = Some(child.clone());
|
|
||||||
} else {
|
|
||||||
return Err(Error::ParseError("Unknown child in content element."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(content)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Content> for Element {
|
|
||||||
fn from(content: Content) -> Element {
|
|
||||||
Element::builder("content")
|
|
||||||
.ns(ns::JINGLE)
|
|
||||||
.attr("creator", content.creator)
|
|
||||||
.attr("disposition", content.disposition)
|
|
||||||
.attr("name", content.name)
|
|
||||||
.attr("senders", content.senders)
|
|
||||||
.append(content.description)
|
|
||||||
.append(content.transport)
|
|
||||||
.append(content.security)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Reason {
|
pub enum Reason {
|
||||||
AlternativeSession, //(String),
|
AlternativeSession, //(String),
|
||||||
|
|
|
||||||
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 {
|
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),+]) => (
|
($(#[$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: Vec<$child_type> = ($child_name, $child_ns) => $child_constructor),+]);
|
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),+]) => (
|
($(#[$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: Vec<$child_type> = ($child_name, $child_ns) => $child_constructor),+]);
|
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])*
|
$(#[$meta])*
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct $elem {
|
pub struct $elem {
|
||||||
|
|
@ -441,7 +523,7 @@ macro_rules! generate_element_with_children {
|
||||||
)*
|
)*
|
||||||
$(
|
$(
|
||||||
$(#[$child_meta])*
|
$(#[$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> {
|
fn try_from(elem: ::minidom::Element) -> Result<$elem, ::error::Error> {
|
||||||
check_self!(elem, $name, $ns);
|
check_self!(elem, $name, $ns);
|
||||||
check_no_unknown_attributes!(elem, $name, [$($attr_name),*]);
|
check_no_unknown_attributes!(elem, $name, [$($attr_name),*]);
|
||||||
let mut parsed_children = vec!();
|
$(
|
||||||
|
start_parse_elem!($child_ident: $coucou);
|
||||||
|
)*
|
||||||
for child in elem.children() {
|
for child in elem.children() {
|
||||||
$(
|
$(
|
||||||
if child.is($child_name, ::ns::$child_ns) {
|
if child.is($child_name, ::ns::$child_ns) {
|
||||||
let parsed_child = $child_constructor::try_from(child.clone())?;
|
do_parse_elem!($child_ident: $coucou = $child_constructor => child);
|
||||||
parsed_children.push(parsed_child);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
|
|
@ -467,7 +550,7 @@ macro_rules! generate_element_with_children {
|
||||||
$attr: get_attr!(elem, $attr_name, $attr_action),
|
$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)
|
.attr($attr_name, elem.$attr)
|
||||||
)*
|
)*
|
||||||
$(
|
$(
|
||||||
.append(elem.$child_ident)
|
.append(generate_serialiser!(elem, $child_ident, $coucou, $child_constructor, ($child_name, $child_ns)))
|
||||||
)*
|
)*
|
||||||
.build()
|
.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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
112
src/mam.rs
112
src/mam.rs
|
|
@ -18,13 +18,17 @@ use forwarding::Forwarded;
|
||||||
|
|
||||||
use ns;
|
use ns;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
generate_element_with_children!(
|
||||||
pub struct Query {
|
Query, "query", MAM,
|
||||||
pub queryid: Option<String>,
|
attributes: [
|
||||||
pub node: Option<String>,
|
queryid: Option<String> = "queryid" => optional,
|
||||||
pub form: Option<DataForm>,
|
node: Option<String> = "node" => optional
|
||||||
pub set: Option<Set>,
|
],
|
||||||
}
|
children: [
|
||||||
|
form: Option<DataForm> = ("x", DATA_FORMS) => DataForm,
|
||||||
|
set: Option<Set> = ("set", RSM) => Set
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
impl IqGetPayload for Query {}
|
impl IqGetPayload for Query {}
|
||||||
impl IqSetPayload for Query {}
|
impl IqSetPayload for Query {}
|
||||||
|
|
@ -36,16 +40,24 @@ generate_element_with_children!(
|
||||||
id: String = "id" => required,
|
id: String = "id" => required,
|
||||||
queryid: String = "queryid" => required,
|
queryid: String = "queryid" => required,
|
||||||
],
|
],
|
||||||
child: (
|
children: [
|
||||||
forwarded: Forwarded = ("forwarded", FORWARD) => Forwarded
|
forwarded: Required<Forwarded> = ("forwarded", FORWARD) => Forwarded
|
||||||
)
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
generate_attribute!(
|
||||||
pub struct Fin {
|
Complete, "complete", bool
|
||||||
pub complete: bool,
|
);
|
||||||
pub set: Set,
|
|
||||||
}
|
generate_element_with_children!(
|
||||||
|
Fin, "fin", MAM,
|
||||||
|
attributes: [
|
||||||
|
complete: Complete = "complete" => default
|
||||||
|
],
|
||||||
|
children: [
|
||||||
|
set: Required<Set> = ("set", RSM) => Set
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
impl IqResultPayload for Fin {}
|
impl IqResultPayload for Fin {}
|
||||||
|
|
||||||
|
|
@ -66,54 +78,6 @@ impl IqGetPayload for Prefs {}
|
||||||
impl IqSetPayload for Prefs {}
|
impl IqSetPayload for Prefs {}
|
||||||
impl IqResultPayload for Prefs {}
|
impl IqResultPayload for Prefs {}
|
||||||
|
|
||||||
impl TryFrom<Element> for Query {
|
|
||||||
type Err = Error;
|
|
||||||
|
|
||||||
fn try_from(elem: Element) -> Result<Query, Error> {
|
|
||||||
check_self!(elem, "query", MAM);
|
|
||||||
check_no_unknown_attributes!(elem, "query", ["queryid", "node"]);
|
|
||||||
let mut form = None;
|
|
||||||
let mut set = None;
|
|
||||||
for child in elem.children() {
|
|
||||||
if child.is("x", ns::DATA_FORMS) {
|
|
||||||
form = Some(DataForm::try_from(child.clone())?);
|
|
||||||
} else if child.is("set", ns::RSM) {
|
|
||||||
set = Some(Set::try_from(child.clone())?);
|
|
||||||
} else {
|
|
||||||
return Err(Error::ParseError("Unknown child in query element."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let queryid = get_attr!(elem, "queryid", optional);
|
|
||||||
let node = get_attr!(elem, "node", optional);
|
|
||||||
Ok(Query { queryid, node, form, set })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<Element> for Fin {
|
|
||||||
type Err = Error;
|
|
||||||
|
|
||||||
fn try_from(elem: Element) -> Result<Fin, Error> {
|
|
||||||
check_self!(elem, "fin", MAM);
|
|
||||||
check_no_unknown_attributes!(elem, "fin", ["complete"]);
|
|
||||||
let mut set = None;
|
|
||||||
for child in elem.children() {
|
|
||||||
if child.is("set", ns::RSM) {
|
|
||||||
set = Some(Set::try_from(child.clone())?);
|
|
||||||
} else {
|
|
||||||
return Err(Error::ParseError("Unknown child in fin element."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let set = set.ok_or(Error::ParseError("Mandatory set element missing in fin."))?;
|
|
||||||
let complete = match elem.attr("complete") {
|
|
||||||
Some(complete) if complete == "true" => true,
|
|
||||||
Some(complete) if complete == "false" => false,
|
|
||||||
None => false,
|
|
||||||
Some(_) => return Err(Error::ParseError("Invalid value for 'complete' attribute.")),
|
|
||||||
};
|
|
||||||
Ok(Fin { complete, set })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<Element> for Prefs {
|
impl TryFrom<Element> for Prefs {
|
||||||
type Err = Error;
|
type Err = Error;
|
||||||
|
|
||||||
|
|
@ -146,28 +110,6 @@ impl TryFrom<Element> for Prefs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Query> for Element {
|
|
||||||
fn from(query: Query) -> Element {
|
|
||||||
Element::builder("query")
|
|
||||||
.ns(ns::MAM)
|
|
||||||
.attr("queryid", query.queryid)
|
|
||||||
.attr("node", query.node)
|
|
||||||
//.append(query.form)
|
|
||||||
.append(query.set)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Fin> for Element {
|
|
||||||
fn from(fin: Fin) -> Element {
|
|
||||||
Element::builder("fin")
|
|
||||||
.ns(ns::MAM)
|
|
||||||
.attr("complete", if fin.complete { Some("true") } else { None })
|
|
||||||
.append(fin.set)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialise_jid_list(name: &str, jids: Vec<Jid>) -> Option<Element> {
|
fn serialise_jid_list(name: &str, jids: Vec<Jid>) -> Option<Element> {
|
||||||
if jids.is_empty() {
|
if jids.is_empty() {
|
||||||
None
|
None
|
||||||
|
|
|
||||||
|
|
@ -5,53 +5,18 @@
|
||||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
// 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/.
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
use try_from::TryFrom;
|
generate_element_with_children!(
|
||||||
|
Muc, "x", MUC, children: [
|
||||||
use minidom::Element;
|
password: Option<String> = ("password", MUC) => String
|
||||||
|
]
|
||||||
use error::Error;
|
);
|
||||||
|
|
||||||
use ns;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Muc {
|
|
||||||
pub password: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<Element> for Muc {
|
|
||||||
type Err = Error;
|
|
||||||
|
|
||||||
fn try_from(elem: Element) -> Result<Muc, Error> {
|
|
||||||
check_self!(elem, "x", MUC);
|
|
||||||
check_no_attributes!(elem, "x");
|
|
||||||
|
|
||||||
let mut password = None;
|
|
||||||
for child in elem.children() {
|
|
||||||
if child.is("password", ns::MUC) {
|
|
||||||
password = Some(child.text());
|
|
||||||
} else {
|
|
||||||
return Err(Error::ParseError("Unknown child in x element."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Muc {
|
|
||||||
password: password,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Muc> for Element {
|
|
||||||
fn from(muc: Muc) -> Element {
|
|
||||||
Element::builder("x")
|
|
||||||
.ns(ns::MUC)
|
|
||||||
.append(muc.password)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use try_from::TryFrom;
|
||||||
|
use minidom::Element;
|
||||||
|
use error::Error;
|
||||||
use compare_elements::NamespaceAwareCompare;
|
use compare_elements::NamespaceAwareCompare;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
140
src/muc/user.rs
140
src/muc/user.rs
|
|
@ -5,7 +5,7 @@
|
||||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
// 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/.
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
use try_from::{TryFrom, TryInto};
|
use try_from::TryFrom;
|
||||||
|
|
||||||
use minidom::Element;
|
use minidom::Element;
|
||||||
|
|
||||||
|
|
@ -80,6 +80,7 @@ Status, "status", MUC_USER, "code", {
|
||||||
/// Optional <actor/> element used in <item/> elements inside presence stanzas of type
|
/// Optional <actor/> element used in <item/> elements inside presence stanzas of type
|
||||||
/// "unavailable" that are sent to users who are kick or banned, as well as within IQs for tracking
|
/// "unavailable" that are sent to users who are kick or banned, as well as within IQs for tracking
|
||||||
/// purposes. -- CHANGELOG 0.17 (2002-10-23)
|
/// purposes. -- CHANGELOG 0.17 (2002-10-23)
|
||||||
|
///
|
||||||
/// Possesses a 'jid' and a 'nick' attribute, so that an action can be attributed either to a real
|
/// Possesses a 'jid' and a 'nick' attribute, so that an action can be attributed either to a real
|
||||||
/// JID or to a roomnick. -- CHANGELOG 1.25 (2012-02-08)
|
/// JID or to a roomnick. -- CHANGELOG 1.25 (2012-02-08)
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
|
@ -140,108 +141,25 @@ generate_attribute!(Role, "role", {
|
||||||
None => "none",
|
None => "none",
|
||||||
}, Default = None);
|
}, Default = None);
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
generate_element_with_children!(
|
||||||
pub struct Item {
|
Item, "item", MUC_USER, attributes: [
|
||||||
pub affiliation: Affiliation,
|
affiliation: Affiliation = "affiliation" => required,
|
||||||
pub jid: Option<Jid>,
|
jid: Option<Jid> = "jid" => optional,
|
||||||
pub nick: Option<String>,
|
nick: Option<String> = "nick" => optional,
|
||||||
pub role: Role,
|
role: Role = "role" => required
|
||||||
pub actor: Option<Actor>,
|
], children: [
|
||||||
pub continue_: Option<Continue>,
|
actor: Option<Actor> = ("actor", MUC_USER) => Actor,
|
||||||
pub reason: Option<Reason>,
|
continue_: Option<Continue> = ("continue", MUC_USER) => Continue,
|
||||||
}
|
reason: Option<Reason> = ("reason", MUC_USER) => Reason
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
impl TryFrom<Element> for Item {
|
generate_element_with_children!(
|
||||||
type Err = Error;
|
MucUser, "x", MUC_USER, children: [
|
||||||
|
status: Vec<Status> = ("status", MUC_USER) => Status,
|
||||||
fn try_from(elem: Element) -> Result<Item, Error> {
|
items: Vec<Item> = ("item", MUC_USER) => Item
|
||||||
check_self!(elem, "item", MUC_USER);
|
]
|
||||||
check_no_unknown_attributes!(elem, "item", ["affiliation", "jid", "nick", "role"]);
|
);
|
||||||
let mut actor: Option<Actor> = None;
|
|
||||||
let mut continue_: Option<Continue> = None;
|
|
||||||
let mut reason: Option<Reason> = None;
|
|
||||||
for child in elem.children() {
|
|
||||||
if child.is("actor", ns::MUC_USER) {
|
|
||||||
actor = Some(child.clone().try_into()?);
|
|
||||||
} else if child.is("continue", ns::MUC_USER) {
|
|
||||||
continue_ = Some(child.clone().try_into()?);
|
|
||||||
} else if child.is("reason", ns::MUC_USER) {
|
|
||||||
reason = Some(child.clone().try_into()?);
|
|
||||||
} else {
|
|
||||||
return Err(Error::ParseError("Unknown child in item element."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let affiliation: Affiliation = get_attr!(elem, "affiliation", required);
|
|
||||||
let jid: Option<Jid> = get_attr!(elem, "jid", optional);
|
|
||||||
let nick: Option<String> = get_attr!(elem, "nick", optional);
|
|
||||||
let role: Role = get_attr!(elem, "role", required);
|
|
||||||
|
|
||||||
Ok(Item{
|
|
||||||
affiliation: affiliation,
|
|
||||||
jid: jid,
|
|
||||||
nick: nick,
|
|
||||||
role: role,
|
|
||||||
actor: actor,
|
|
||||||
continue_: continue_,
|
|
||||||
reason: reason,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Item> for Element {
|
|
||||||
fn from(item: Item) -> Element {
|
|
||||||
Element::builder("item")
|
|
||||||
.ns(ns::MUC_USER)
|
|
||||||
.attr("affiliation", item.affiliation)
|
|
||||||
.attr("jid", item.jid)
|
|
||||||
.attr("nick", item.nick)
|
|
||||||
.attr("role", item.role)
|
|
||||||
.append(item.actor)
|
|
||||||
.append(item.continue_)
|
|
||||||
.append(item.reason)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct MucUser {
|
|
||||||
pub status: Vec<Status>,
|
|
||||||
pub items: Vec<Item>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<Element> for MucUser {
|
|
||||||
type Err = Error;
|
|
||||||
|
|
||||||
fn try_from(elem: Element) -> Result<MucUser, Error> {
|
|
||||||
check_self!(elem, "x", MUC_USER);
|
|
||||||
check_no_attributes!(elem, "x");
|
|
||||||
let mut status = vec!();
|
|
||||||
let mut items = vec!();
|
|
||||||
for child in elem.children() {
|
|
||||||
if child.is("status", ns::MUC_USER) {
|
|
||||||
status.push(Status::try_from(child.clone())?);
|
|
||||||
} else if child.is("item", ns::MUC_USER) {
|
|
||||||
items.push(Item::try_from(child.clone())?);
|
|
||||||
} else {
|
|
||||||
return Err(Error::ParseError("Unknown child in x element."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(MucUser {
|
|
||||||
status,
|
|
||||||
items,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<MucUser> for Element {
|
|
||||||
fn from(muc_user: MucUser) -> Element {
|
|
||||||
Element::builder("x")
|
|
||||||
.ns(ns::MUC_USER)
|
|
||||||
.append(muc_user.status)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
@ -257,6 +175,24 @@ mod tests {
|
||||||
MucUser::try_from(elem).unwrap();
|
MucUser::try_from(elem).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn statuses_and_items() {
|
||||||
|
let elem: Element = "
|
||||||
|
<x xmlns='http://jabber.org/protocol/muc#user'>
|
||||||
|
<status code='101'/>
|
||||||
|
<status code='102'/>
|
||||||
|
<item affiliation='member' role='moderator'/>
|
||||||
|
</x>
|
||||||
|
".parse().unwrap();
|
||||||
|
let muc_user = MucUser::try_from(elem).unwrap();
|
||||||
|
assert_eq!(muc_user.status.len(), 2);
|
||||||
|
assert_eq!(muc_user.status[0], Status::AffiliationChange);
|
||||||
|
assert_eq!(muc_user.status[1], Status::ConfigShowsUnavailableMembers);
|
||||||
|
assert_eq!(muc_user.items.len(), 1);
|
||||||
|
assert_eq!(muc_user.items[0].affiliation, Affiliation::Member);
|
||||||
|
assert_eq!(muc_user.items[0].role, Role::Moderator);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_invalid_child() {
|
fn test_invalid_child() {
|
||||||
let elem: Element = "
|
let elem: Element = "
|
||||||
|
|
|
||||||
|
|
@ -72,10 +72,10 @@ generate_element_with_only_attributes!(
|
||||||
generate_element_with_children!(
|
generate_element_with_children!(
|
||||||
/// Request to configure a new node.
|
/// Request to configure a new node.
|
||||||
Configure, "configure", PUBSUB,
|
Configure, "configure", PUBSUB,
|
||||||
child: (
|
children: [
|
||||||
/// The form to configure it.
|
/// The form to configure it.
|
||||||
form: Option<DataForm> = ("x", DATA_FORMS) => DataForm
|
form: Option<DataForm> = ("x", DATA_FORMS) => DataForm
|
||||||
)
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
generate_element_with_only_attributes!(
|
generate_element_with_only_attributes!(
|
||||||
|
|
@ -168,10 +168,10 @@ generate_element_with_children!(
|
||||||
/// The subscription identifier affected by this request.
|
/// The subscription identifier affected by this request.
|
||||||
subid: Option<SubscriptionId> = "subid" => optional,
|
subid: Option<SubscriptionId> = "subid" => optional,
|
||||||
],
|
],
|
||||||
child: (
|
children: [
|
||||||
/// The form describing the subscription.
|
/// The form describing the subscription.
|
||||||
form: Option<DataForm> = ("x", DATA_FORMS) => DataForm
|
form: Option<DataForm> = ("x", DATA_FORMS) => DataForm
|
||||||
)
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
generate_element_with_children!(
|
generate_element_with_children!(
|
||||||
|
|
@ -190,10 +190,10 @@ generate_element_with_children!(
|
||||||
generate_element_with_children!(
|
generate_element_with_children!(
|
||||||
/// The options associated to a publish request.
|
/// The options associated to a publish request.
|
||||||
PublishOptions, "publish-options", PUBSUB,
|
PublishOptions, "publish-options", PUBSUB,
|
||||||
child: (
|
children: [
|
||||||
/// The form describing these options.
|
/// The form describing these options.
|
||||||
form: Option<DataForm> = ("x", DATA_FORMS) => DataForm
|
form: Option<DataForm> = ("x", DATA_FORMS) => DataForm
|
||||||
)
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
generate_attribute!(
|
generate_attribute!(
|
||||||
|
|
@ -300,10 +300,10 @@ generate_element_with_children!(
|
||||||
/// The state of the subscription.
|
/// The state of the subscription.
|
||||||
subscription: Option<Subscription> = "subscription" => optional,
|
subscription: Option<Subscription> = "subscription" => optional,
|
||||||
],
|
],
|
||||||
child: (
|
children: [
|
||||||
/// The options related to this subscription.
|
/// The options related to this subscription.
|
||||||
subscribe_options: Option<SubscribeOptions> = ("subscribe-options", PUBSUB) => SubscribeOptions
|
subscribe_options: Option<SubscribeOptions> = ("subscribe-options", PUBSUB) => SubscribeOptions
|
||||||
)
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
generate_element_with_only_attributes!(
|
generate_element_with_only_attributes!(
|
||||||
|
|
|
||||||
|
|
@ -62,10 +62,10 @@ generate_element_with_children!(
|
||||||
attributes: [
|
attributes: [
|
||||||
h: Option<u32> = "h" => optional,
|
h: Option<u32> = "h" => optional,
|
||||||
],
|
],
|
||||||
child: (
|
children: [
|
||||||
// XXX: implement the * handling.
|
// XXX: implement the * handling.
|
||||||
error: Option<DefinedCondition> = ("*", XMPP_STANZAS) => DefinedCondition
|
error: Option<DefinedCondition> = ("*", XMPP_STANZAS) => DefinedCondition
|
||||||
)
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
generate_empty_element!(
|
generate_empty_element!(
|
||||||
|
|
|
||||||
|
|
@ -4,84 +4,25 @@
|
||||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
// 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/.
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
use try_from::TryFrom;
|
|
||||||
use minidom::Element;
|
|
||||||
use error::Error;
|
|
||||||
use ns;
|
|
||||||
use iq::{IqGetPayload, IqResultPayload};
|
use iq::{IqGetPayload, IqResultPayload};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
generate_element_with_children!(
|
||||||
pub struct Version {
|
Version, "query", VERSION,
|
||||||
pub name: String,
|
children: [
|
||||||
pub version: String,
|
name: Required<String> = ("name", VERSION) => String,
|
||||||
pub os: Option<String>,
|
version: Required<String> = ("version", VERSION) => String,
|
||||||
}
|
os: Option<String> = ("os", VERSION) => String
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
impl IqGetPayload for Version {}
|
impl IqGetPayload for Version {}
|
||||||
impl IqResultPayload for Version {}
|
impl IqResultPayload for Version {}
|
||||||
|
|
||||||
impl TryFrom<Element> for Version {
|
|
||||||
type Err = Error;
|
|
||||||
|
|
||||||
fn try_from(elem: Element) -> Result<Version, Error> {
|
|
||||||
check_self!(elem, "query", VERSION, "version");
|
|
||||||
check_no_attributes!(elem, "version");
|
|
||||||
let mut name = None;
|
|
||||||
let mut version = None;
|
|
||||||
let mut os = None;
|
|
||||||
for child in elem.children() {
|
|
||||||
if child.is("name", ns::VERSION) {
|
|
||||||
if name.is_some() {
|
|
||||||
return Err(Error::ParseError("More than one name in version element."));
|
|
||||||
}
|
|
||||||
name = Some(child.text());
|
|
||||||
} else if child.is("version", ns::VERSION) {
|
|
||||||
if version.is_some() {
|
|
||||||
return Err(Error::ParseError("More than one version in version element."));
|
|
||||||
}
|
|
||||||
version = Some(child.text());
|
|
||||||
} else if child.is("os", ns::VERSION) {
|
|
||||||
if os.is_some() {
|
|
||||||
return Err(Error::ParseError("More than one os in version element."));
|
|
||||||
}
|
|
||||||
os = Some(child.text());
|
|
||||||
} else {
|
|
||||||
return Err(Error::ParseError("Unknown child in version element."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let name = name.unwrap();
|
|
||||||
let version = version.unwrap();
|
|
||||||
Ok(Version {
|
|
||||||
name,
|
|
||||||
version,
|
|
||||||
os,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Version> for Element {
|
|
||||||
fn from(version: Version) -> Element {
|
|
||||||
Element::builder("query")
|
|
||||||
.ns(ns::VERSION)
|
|
||||||
.append(Element::builder("name")
|
|
||||||
.ns(ns::VERSION)
|
|
||||||
.append(version.name)
|
|
||||||
.build())
|
|
||||||
.append(Element::builder("version")
|
|
||||||
.ns(ns::VERSION)
|
|
||||||
.append(version.version)
|
|
||||||
.build())
|
|
||||||
.append(Element::builder("os")
|
|
||||||
.ns(ns::VERSION)
|
|
||||||
.append(version.os)
|
|
||||||
.build())
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use try_from::TryFrom;
|
||||||
|
use minidom::Element;
|
||||||
use compare_elements::NamespaceAwareCompare;
|
use compare_elements::NamespaceAwareCompare;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue