Detailed changes
@@ -13,39 +13,14 @@ use error::Error;
use ns;
/// Structure representing an `<encryption xmlns='urn:xmpp:eme:0'/>` 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<String>,
-}
-
-impl TryFrom<Element> for ExplicitMessageEncryption {
- type Err = Error;
-
- fn try_from(elem: Element) -> Result<ExplicitMessageEncryption, Error> {
- 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<ExplicitMessageEncryption> 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<String> = "name" => optional,
+]);
#[cfg(test)]
mod tests {
@@ -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<Element> for Open {
- type Err = Error;
-
- fn try_from(elem: Element) -> Result<Open, Error> {
- 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<Open> 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<Data> for Element {
}
}
-#[derive(Debug, Clone)]
-pub struct Close {
- pub sid: String,
-}
-
-impl TryFrom<Element> for Close {
- type Err = Error;
-
- fn try_from(elem: Element) -> Result<Close, Error> {
- 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<Close> 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 {
@@ -256,35 +256,10 @@ impl From<Checksum> for Element {
}
}
-#[derive(Debug, Clone)]
-pub struct Received {
- pub name: ContentId,
- pub creator: Creator,
-}
-
-impl TryFrom<Element> for Received {
- type Err = Error;
-
- fn try_from(elem: Element) -> Result<Received, Error> {
- 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<Received> 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 {
@@ -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<Element> for Transport {
- type Err = Error;
-
- fn try_from(elem: Element) -> Result<Transport, Error> {
- 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<Transport> 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 {
@@ -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<u16>,
- pub priority: u32,
- pub type_: Type,
-}
-
-impl From<Candidate> 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<u16> = "port" => optional,
+ priority: u32 = "priority" => required,
+ type_: Type = "type" => default,
+]);
#[derive(Debug, Clone)]
pub enum TransportPayload {
@@ -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<Element> 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)]
@@ -12,31 +12,9 @@ use error::Error;
use ns;
-#[derive(Debug, Clone)]
-pub struct Replace {
- pub id: String,
-}
-
-impl TryFrom<Element> for Replace {
- type Err = Error;
-
- fn try_from(elem: Element) -> Result<Replace, Error> {
- 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<Replace> 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 {
@@ -192,38 +192,9 @@ impl From<Actor> for Element {
}
}
-#[derive(Debug, Clone, PartialEq)]
-pub struct Continue {
- thread: Option<String>,
-}
-
-impl TryFrom<Element> for Continue {
- type Err = Error;
-
- fn try_from(elem: Element) -> Result<Continue, Error> {
- 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<Continue> 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<String> = "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!(),
}
}
@@ -12,68 +12,11 @@ use error::Error;
use ns;
-#[derive(Debug, Clone)]
-pub struct Request;
+generate_empty_element!(Request, "request", ns::RECEIPTS);
-impl TryFrom<Element> for Request {
- type Err = Error;
-
- fn try_from(elem: Element) -> Result<Request, Error> {
- 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<Request> for Element {
- fn from(_: Request) -> Element {
- Element::builder("request")
- .ns(ns::RECEIPTS)
- .build()
- }
-}
-
-#[derive(Debug, Clone)]
-pub struct Received {
- pub id: Option<String>,
-}
-
-impl TryFrom<Element> for Received {
- type Err = Error;
-
- fn try_from(elem: Element) -> Result<Received, Error> {
- 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<Received> 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<String> = "id" => optional,
+]);
#[cfg(test)]
mod tests {
@@ -13,68 +13,14 @@ use error::Error;
use ns;
-#[derive(Debug, Clone)]
-pub struct StanzaId {
- pub id: String,
- pub by: Jid,
-}
-
-impl TryFrom<Element> for StanzaId {
- type Err = Error;
-
- fn try_from(elem: Element) -> Result<StanzaId, Error> {
- 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<StanzaId> 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<Element> for OriginId {
- type Err = Error;
-
- fn try_from(elem: Element) -> Result<OriginId, Error> {
- 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<OriginId> 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 {