disco: Use a macro for <identity/>.

This commit is contained in:
Emmanuel Gil Peyrot 2019-02-28 02:26:10 +01:00
parent c4d867571e
commit b56582c8b5
2 changed files with 40 additions and 61 deletions

View file

@ -43,21 +43,25 @@ impl Feature {
}
}
generate_element!(
/// Structure representing an `<identity xmlns='http://jabber.org/protocol/disco#info'/>` element.
#[derive(Debug, Clone)]
pub struct Identity {
Identity, "identity", DISCO_INFO,
attributes: [
/// Category of this identity.
pub category: String, // TODO: use an enum here.
// TODO: use an enum here.
category: RequiredNonEmpty<String> = "category",
/// Type of this identity.
pub type_: String, // TODO: use an enum here.
// TODO: use an enum here.
type_: RequiredNonEmpty<String> = "type",
/// Lang of the name of this identity.
pub lang: Option<String>,
lang: Option<String> = "xml:lang",
/// Name of this identity.
pub name: Option<String>,
}
name: Option<String> = "name",
]
);
impl Identity {
/// Create a new `<identity/>`.
@ -89,53 +93,6 @@ impl Identity {
}
}
impl TryFrom<Element> for Identity {
type Err = Error;
fn try_from(elem: Element) -> Result<Identity, Error> {
check_self!(elem, "identity", DISCO_INFO, "disco#info identity");
check_no_children!(elem, "disco#info identity");
check_no_unknown_attributes!(
elem,
"disco#info identity",
["category", "type", "xml:lang", "name"]
);
let category = get_attr!(elem, "category", Required);
if category == "" {
return Err(Error::ParseError(
"Identity must have a non-empty 'category' attribute.",
));
}
let type_ = get_attr!(elem, "type", Required);
if type_ == "" {
return Err(Error::ParseError(
"Identity must have a non-empty 'type' attribute.",
));
}
Ok(Identity {
category,
type_,
lang: get_attr!(elem, "xml:lang", Option),
name: get_attr!(elem, "name", Option),
})
}
}
impl From<Identity> for Element {
fn from(identity: Identity) -> Element {
Element::builder("identity")
.ns(ns::DISCO_INFO)
.attr("category", identity.category)
.attr("type", identity.type_)
.attr("xml:lang", identity.lang)
.attr("name", identity.name)
.build()
}
}
/// Structure representing a `<query xmlns='http://jabber.org/protocol/disco#info'/>` element.
///
/// It should only be used in an `<iq type='result'/>`, as it can only
@ -385,7 +342,7 @@ mod tests {
};
assert_eq!(
message,
"Identity must have a non-empty 'category' attribute."
"Required attribute 'category' must not be empty."
);
let elem: Element = "<query xmlns='http://jabber.org/protocol/disco#info'><identity category='coucou'/></query>".parse().unwrap();
@ -402,7 +359,7 @@ mod tests {
Error::ParseError(string) => string,
_ => panic!(),
};
assert_eq!(message, "Identity must have a non-empty 'type' attribute.");
assert_eq!(message, "Required attribute 'type' must not be empty.");
}
#[test]

View file

@ -33,6 +33,25 @@ macro_rules! get_attr {
}
}
};
($elem:ident, $attr:tt, RequiredNonEmpty, $value:ident, $func:expr) => {
match $elem.attr($attr) {
Some("") => {
return Err(crate::util::error::Error::ParseError(concat!(
"Required attribute '",
$attr,
"' must not be empty."
)));
},
Some($value) => $func,
None => {
return Err(crate::util::error::Error::ParseError(concat!(
"Required attribute '",
$attr,
"' missing."
)));
}
}
};
($elem:ident, $attr:tt, Default, $value:ident, $func:expr) => {
match $elem.attr($attr) {
Some($value) => $func,
@ -408,6 +427,9 @@ macro_rules! decl_attr {
(Required, $type:ty) => (
$type
);
(RequiredNonEmpty, $type:ty) => (
$type
);
(Default, $type:ty) => (
$type
);