Add a generate_element_with_only_attributes macro, and use it wherever it makes sense.
This commit is contained in:
parent
ed53f452c3
commit
929bd577f3
10 changed files with 92 additions and 365 deletions
39
src/eme.rs
39
src/eme.rs
|
|
@ -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 {
|
||||
|
|
|
|||
72
src/ibb.rs
72
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<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 {
|
||||
|
|
|
|||
40
src/lib.rs
40
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<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,
|
||||
}
|
||||
generate_element_with_only_attributes!(StanzaId, "stanza-id", ns::SID, [
|
||||
id: String = "id" => required,
|
||||
by: Jid = "by" => required,
|
||||
]);
|
||||
|
||||
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!(OriginId, "origin-id", ns::SID, [
|
||||
id: String = "id" => required,
|
||||
]);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
|
|||
Loading…
Reference in a new issue