diff --git a/src/eme.rs b/src/eme.rs
index ad4b437f8098a5cc18551277f7b03ce4eebf4210..540b50730df1036c450f80478b44fd77fa1738ca 100644
--- a/src/eme.rs
+++ b/src/eme.rs
@@ -13,39 +13,14 @@ use error::Error;
use ns;
/// Structure representing an `` element.
-#[derive(Debug, Clone)]
-pub struct ExplicitMessageEncryption {
- /// Namespace of the encryption scheme used.
- pub namespace: String,
+generate_element_with_only_attributes!(ExplicitMessageEncryption, "encryption", ns::EME, [
+ // Namespace of the encryption scheme used.
+ namespace: String = "namespace" => required,
- /// User-friendly name for the encryption scheme, should be `None` for OTR,
- /// legacy OpenPGP and OX.
- pub name: Option,
-}
-
-impl TryFrom for ExplicitMessageEncryption {
- type Err = Error;
-
- fn try_from(elem: Element) -> Result {
- check_self!(elem, "encryption", ns::EME);
- check_no_children!(elem, "encryption");
- check_no_unknown_attributes!(elem, "encryption", ["namespace", "name"]);
- Ok(ExplicitMessageEncryption {
- namespace: get_attr!(elem, "namespace", required),
- name: get_attr!(elem, "name", optional),
- })
- }
-}
-
-impl From for Element {
- fn from(eme: ExplicitMessageEncryption) -> Element {
- Element::builder("encryption")
- .ns(ns::EME)
- .attr("namespace", eme.namespace)
- .attr("name", eme.name)
- .build()
- }
-}
+ // User-friendly name for the encryption scheme, should be `None` for OTR,
+ // legacy OpenPGP and OX.
+ name: Option = "name" => optional,
+]);
#[cfg(test)]
mod tests {
diff --git a/src/ibb.rs b/src/ibb.rs
index 2c01e1c741aa9785c5a308471f5bbfea2ed9e9d5..7d7f3e73fa501e4a7ffd63e1586bac52ba8532ee 100644
--- a/src/ibb.rs
+++ b/src/ibb.rs
@@ -19,41 +19,11 @@ generate_attribute!(Stanza, "stanza", {
Message => "message",
}, Default = Iq);
-#[derive(Debug, Clone)]
-pub struct Open {
- pub block_size: u16,
- pub sid: String,
- pub stanza: Stanza,
-}
-
-impl TryFrom for Open {
- type Err = Error;
-
- fn try_from(elem: Element) -> Result {
- if !elem.is("open", ns::IBB) {
- return Err(Error::ParseError("This is not an open element."));
- }
- for _ in elem.children() {
- return Err(Error::ParseError("Unknown child in open element."));
- }
- Ok(Open {
- block_size: get_attr!(elem, "block-size", required),
- sid: get_attr!(elem, "sid", required),
- stanza: get_attr!(elem, "stanza", default),
- })
- }
-}
-
-impl From for Element {
- fn from(open: Open) -> Element {
- Element::builder("open")
- .ns(ns::IBB)
- .attr("block-size", open.block_size)
- .attr("sid", open.sid)
- .attr("stanza", open.stanza)
- .build()
- }
-}
+generate_element_with_only_attributes!(Open, "open", ns::IBB, [
+ block_size: u16 = "block-size" => required,
+ sid: String = "sid" => required,
+ stanza: Stanza = "stanza" => default,
+]);
#[derive(Debug, Clone)]
pub struct Data {
@@ -91,35 +61,9 @@ impl From for Element {
}
}
-#[derive(Debug, Clone)]
-pub struct Close {
- pub sid: String,
-}
-
-impl TryFrom for Close {
- type Err = Error;
-
- fn try_from(elem: Element) -> Result {
- if !elem.is("close", ns::IBB) {
- return Err(Error::ParseError("This is not a close element."));
- }
- for _ in elem.children() {
- return Err(Error::ParseError("Unknown child in close element."));
- }
- Ok(Close {
- sid: get_attr!(elem, "sid", required),
- })
- }
-}
-
-impl From for Element {
- fn from(close: Close) -> Element {
- Element::builder("close")
- .ns(ns::IBB)
- .attr("sid", close.sid)
- .build()
- }
-}
+generate_element_with_only_attributes!(Close, "close", ns::IBB, [
+ sid: String = "sid" => required,
+]);
#[cfg(test)]
mod tests {
diff --git a/src/jingle_ft.rs b/src/jingle_ft.rs
index 7e13351f8a96de92f578241d0197d8e624aeaa95..15a21c67efa16c70df390cb3774b4d3d505a59de 100644
--- a/src/jingle_ft.rs
+++ b/src/jingle_ft.rs
@@ -256,35 +256,10 @@ impl From for Element {
}
}
-#[derive(Debug, Clone)]
-pub struct Received {
- pub name: ContentId,
- pub creator: Creator,
-}
-
-impl TryFrom for Received {
- type Err = Error;
-
- fn try_from(elem: Element) -> Result {
- check_self!(elem, "received", ns::JINGLE_FT);
- check_no_children!(elem, "received");
- check_no_unknown_attributes!(elem, "received", ["name", "creator"]);
- Ok(Received {
- name: get_attr!(elem, "name", required),
- creator: get_attr!(elem, "creator", required),
- })
- }
-}
-
-impl From for Element {
- fn from(received: Received) -> Element {
- Element::builder("received")
- .ns(ns::JINGLE_FT)
- .attr("name", received.name)
- .attr("creator", received.creator)
- .build()
- }
-}
+generate_element_with_only_attributes!(Received, "received", ns::JINGLE_FT, [
+ name: ContentId = "name" => required,
+ creator: Creator = "creator" => required,
+]);
#[cfg(test)]
mod tests {
diff --git a/src/jingle_ibb.rs b/src/jingle_ibb.rs
index ed1c6d189ec5c5662aa4aab3682bd58cde9223a9..632540ed2cc909d22c3625a5e621a1c6565ab498 100644
--- a/src/jingle_ibb.rs
+++ b/src/jingle_ibb.rs
@@ -17,41 +17,11 @@ use ibb::Stanza;
generate_id!(StreamId);
-#[derive(Debug, Clone)]
-pub struct Transport {
- pub block_size: u16,
- pub sid: StreamId,
- pub stanza: Stanza,
-}
-
-impl TryFrom for Transport {
- type Err = Error;
-
- fn try_from(elem: Element) -> Result {
- if !elem.is("transport", ns::JINGLE_IBB) {
- return Err(Error::ParseError("This is not an JingleIBB element."))
- }
- for _ in elem.children() {
- return Err(Error::ParseError("Unknown child in JingleIBB element."));
- }
- Ok(Transport {
- block_size: get_attr!(elem, "block-size", required),
- sid: get_attr!(elem, "sid", required),
- stanza: get_attr!(elem, "stanza", default),
- })
- }
-}
-
-impl From for Element {
- fn from(transport: Transport) -> Element {
- Element::builder("transport")
- .ns(ns::JINGLE_IBB)
- .attr("block-size", transport.block_size)
- .attr("sid", transport.sid)
- .attr("stanza", transport.stanza)
- .build()
- }
-}
+generate_element_with_only_attributes!(Transport, "transport", ns::JINGLE_IBB, [
+ block_size: u16 = "block-size" => required,
+ sid: StreamId = "sid" => required,
+ stanza: Stanza = "stanza" => default,
+]);
#[cfg(test)]
mod tests {
diff --git a/src/jingle_s5b.rs b/src/jingle_s5b.rs
index 6f8bb902106ebcdbdd1dedae5f00fda9c57d53da..f1396c5df4d1d1c1fdf032fa18c324a17cba229e 100644
--- a/src/jingle_s5b.rs
+++ b/src/jingle_s5b.rs
@@ -30,29 +30,14 @@ generate_id!(CandidateId);
generate_id!(StreamId);
-#[derive(Debug, Clone)]
-pub struct Candidate {
- pub cid: CandidateId,
- pub host: String,
- pub jid: Jid,
- pub port: Option,
- pub priority: u32,
- pub type_: Type,
-}
-
-impl From for Element {
- fn from(candidate: Candidate) -> Element {
- Element::builder("candidate")
- .ns(ns::JINGLE_S5B)
- .attr("cid", candidate.cid)
- .attr("host", candidate.host)
- .attr("jid", String::from(candidate.jid))
- .attr("port", candidate.port)
- .attr("priority", candidate.priority)
- .attr("type", candidate.type_)
- .build()
- }
-}
+generate_element_with_only_attributes!(Candidate, "candidate", ns::JINGLE_S5B, [
+ cid: CandidateId = "cid" => required,
+ host: String = "host" => required,
+ jid: Jid = "jid" => required,
+ port: Option = "port" => optional,
+ priority: u32 = "priority" => required,
+ type_: Type = "type" => default,
+]);
#[derive(Debug, Clone)]
pub enum TransportPayload {
diff --git a/src/lib.rs b/src/lib.rs
index ccc84f022575287748020885e952882d986750be..5e767fc20acc13ebb29e75c3cc458985324065e6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -203,6 +203,46 @@ macro_rules! generate_empty_element {
);
}
+macro_rules! generate_element_with_only_attributes {
+ ($elem:ident, $name:tt, $ns:expr, [$($attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),+,]) => (
+ generate_element_with_only_attributes!($elem, $name, $ns, [$($attr: $attr_type = $attr_name => $attr_action),*]);
+ );
+ ($elem:ident, $name:tt, $ns:expr, [$($attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),+]) => (
+ #[derive(Debug, Clone)]
+ pub struct $elem {
+ $(
+ 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)]
diff --git a/src/message_correct.rs b/src/message_correct.rs
index d8200ae19b07401e21a548a6e0b0018e7e4efa1e..26cdcf99596b8c79d8403dabbe108f46e8800d02 100644
--- a/src/message_correct.rs
+++ b/src/message_correct.rs
@@ -12,31 +12,9 @@ use error::Error;
use ns;
-#[derive(Debug, Clone)]
-pub struct Replace {
- pub id: String,
-}
-
-impl TryFrom for Replace {
- type Err = Error;
-
- fn try_from(elem: Element) -> Result {
- check_self!(elem, "replace", ns::MESSAGE_CORRECT);
- check_no_children!(elem, "replace");
- check_no_unknown_attributes!(elem, "replace", ["id"]);
- let id = get_attr!(elem, "id", required);
- Ok(Replace { id })
- }
-}
-
-impl From for Element {
- fn from(replace: Replace) -> Element {
- Element::builder("replace")
- .ns(ns::MESSAGE_CORRECT)
- .attr("id", replace.id)
- .build()
- }
-}
+generate_element_with_only_attributes!(Replace, "replace", ns::MESSAGE_CORRECT, [
+ id: String = "id" => required,
+]);
#[cfg(test)]
mod tests {
diff --git a/src/muc/user.rs b/src/muc/user.rs
index 322525cbe2a3cadbe0a292f23f401947d8c15b3f..fb30967993d0d417959a373a168f9a98232590fd 100644
--- a/src/muc/user.rs
+++ b/src/muc/user.rs
@@ -192,38 +192,9 @@ impl From for Element {
}
}
-#[derive(Debug, Clone, PartialEq)]
-pub struct Continue {
- thread: Option,
-}
-
-impl TryFrom for Continue {
- type Err = Error;
-
- fn try_from(elem: Element) -> Result {
- if !elem.is("continue", ns::MUC_USER) {
- return Err(Error::ParseError("This is not a continue element."));
- }
- for _ in elem.children() {
- return Err(Error::ParseError("Unknown child in continue element."));
- }
- for (attr, _) in elem.attrs() {
- if attr != "thread" {
- return Err(Error::ParseError("Unknown attribute in continue element."));
- }
- }
- Ok(Continue { thread: get_attr!(elem, "thread", optional) })
- }
-}
-
-impl From for Element {
- fn from(cont: Continue) -> Element {
- Element::builder("continue")
- .ns(ns::MUC_USER)
- .attr("thread", cont.thread)
- .build()
- }
-}
+generate_element_with_only_attributes!(Continue, "continue", ns::MUC_USER, [
+ thread: Option = "thread" => optional,
+]);
#[derive(Debug, Clone, PartialEq)]
pub struct Reason(String);
@@ -576,7 +547,7 @@ mod tests {
thread='foo'/>
".parse().unwrap();
let continue_ = Continue::try_from(elem).unwrap();
- assert_eq!(continue_, Continue { thread: Some("foo".to_owned()) });
+ assert_eq!(continue_.thread, Some("foo".to_owned()));
}
#[test]
@@ -725,7 +696,7 @@ mod tests {
let item = Item::try_from(elem).unwrap();
let continue_1 = Continue { thread: Some("foobar".to_owned()) };
match item {
- Item { continue_: Some(continue_2), .. } => assert_eq!(continue_2, continue_1),
+ Item { continue_: Some(continue_2), .. } => assert_eq!(continue_2.thread, continue_1.thread),
_ => panic!(),
}
}
diff --git a/src/receipts.rs b/src/receipts.rs
index 6ccec7eae1f500062175bfdc776eb5e3ac178106..470a46474dde9241e8fc74570fa186429aa0ace9 100644
--- a/src/receipts.rs
+++ b/src/receipts.rs
@@ -12,68 +12,11 @@ use error::Error;
use ns;
-#[derive(Debug, Clone)]
-pub struct Request;
+generate_empty_element!(Request, "request", ns::RECEIPTS);
-impl TryFrom for Request {
- type Err = Error;
-
- fn try_from(elem: Element) -> Result {
- if !elem.is("request", ns::RECEIPTS) {
- return Err(Error::ParseError("This is not a request element."));
- }
- for _ in elem.children() {
- return Err(Error::ParseError("Unknown child in request element."));
- }
- for _ in elem.attrs() {
- return Err(Error::ParseError("Unknown attribute in request element."));
- }
- Ok(Request)
- }
-}
-
-impl From for Element {
- fn from(_: Request) -> Element {
- Element::builder("request")
- .ns(ns::RECEIPTS)
- .build()
- }
-}
-
-#[derive(Debug, Clone)]
-pub struct Received {
- pub id: Option,
-}
-
-impl TryFrom for Received {
- type Err = Error;
-
- fn try_from(elem: Element) -> Result {
- if !elem.is("received", ns::RECEIPTS) {
- return Err(Error::ParseError("This is not a received element."));
- }
- for _ in elem.children() {
- return Err(Error::ParseError("Unknown child in received element."));
- }
- for (attr, _) in elem.attrs() {
- if attr != "id" {
- return Err(Error::ParseError("Unknown attribute in received element."));
- }
- }
- Ok(Received {
- id: get_attr!(elem, "id", optional),
- })
- }
-}
-
-impl From for Element {
- fn from(received: Received) -> Element {
- Element::builder("received")
- .ns(ns::RECEIPTS)
- .attr("id", received.id)
- .build()
- }
-}
+generate_element_with_only_attributes!(Received, "received", ns::RECEIPTS, [
+ id: Option = "id" => optional,
+]);
#[cfg(test)]
mod tests {
diff --git a/src/stanza_id.rs b/src/stanza_id.rs
index feeeadbe0328d00411e776d557227ed9dc7439c4..6e65e012b885d13e0b1458b3687f710743a21746 100644
--- a/src/stanza_id.rs
+++ b/src/stanza_id.rs
@@ -13,68 +13,14 @@ use error::Error;
use ns;
-#[derive(Debug, Clone)]
-pub struct StanzaId {
- pub id: String,
- pub by: Jid,
-}
-
-impl TryFrom for StanzaId {
- type Err = Error;
-
- fn try_from(elem: Element) -> Result {
- if !elem.is("stanza-id", ns::SID) {
- return Err(Error::ParseError("This is not a stanza-id element."));
- }
- for _ in elem.children() {
- return Err(Error::ParseError("Unknown child in stanza-id element."));
- }
- Ok(StanzaId {
- id: get_attr!(elem, "id", required),
- by: get_attr!(elem, "by", required),
- })
- }
-}
-
-impl From for Element {
- fn from(stanza_id: StanzaId) -> Element {
- Element::builder("stanza-id")
- .ns(ns::SID)
- .attr("id", stanza_id.id)
- .attr("by", stanza_id.by)
- .build()
- }
-}
-
-#[derive(Debug, Clone)]
-pub struct OriginId {
- pub id: String,
-}
-
-impl TryFrom for OriginId {
- type Err = Error;
-
- fn try_from(elem: Element) -> Result {
- if !elem.is("origin-id", ns::SID) {
- return Err(Error::ParseError("This is not an origin-id element."));
- }
- for _ in elem.children() {
- return Err(Error::ParseError("Unknown child in origin-id element."));
- }
- Ok(OriginId {
- id: get_attr!(elem, "id", required),
- })
- }
-}
-
-impl From for Element {
- fn from(origin_id: OriginId) -> Element {
- Element::builder("origin-id")
- .ns(ns::SID)
- .attr("id", origin_id.id)
- .build()
- }
-}
+generate_element_with_only_attributes!(StanzaId, "stanza-id", ns::SID, [
+ id: String = "id" => required,
+ by: Jid = "by" => required,
+]);
+
+generate_element_with_only_attributes!(OriginId, "origin-id", ns::SID, [
+ id: String = "id" => required,
+]);
#[cfg(test)]
mod tests {