diff --git a/parsers/src/bind2.rs b/parsers/src/bind2.rs index 4b76d378dd6b767651de30e530a53fcb6ae70cfc..4c31965326da0906cbce4b9f04c7a53a6122dc0c 100644 --- a/parsers/src/bind2.rs +++ b/parsers/src/bind2.rs @@ -9,7 +9,6 @@ use xso::{AsXml, FromXml}; use crate::mam; use crate::ns; use minidom::Element; -use xso::error::{Error, FromElementError}; /// Represents the `` element, as sent by the server in SASL 2 to advertise which features /// can be enabled during the binding step. @@ -17,112 +16,41 @@ use xso::error::{Error, FromElementError}; #[xml(namespace = ns::BIND2, name = "bind")] pub struct BindFeature { /// The features that can be enabled by the client. - #[xml(extract(name = "inline", fields(extract(n = .., name = "feature", fields(attribute(name = "var", type_ = String))))))] + #[xml(extract(default, name = "inline", fields(extract(n = .., name = "feature", fields(attribute(name = "var", type_ = String))))))] pub inline_features: Vec, } /// Represents a `` element, as sent by the client inline in the `` SASL 2 /// element, to perform the binding at the same time as the authentication. -#[derive(Debug, Clone, PartialEq)] +#[derive(FromXml, AsXml, Debug, Clone, PartialEq)] +#[xml(namespace = ns::BIND2, name = "bind")] pub struct BindQuery { /// Short text string that typically identifies the software the user is using, mostly useful /// for diagnostic purposes for users, operators and developers. This tag may be visible to /// other entities on the XMPP network. + #[xml(extract(default, fields(text(type_ = String))))] pub tag: Option, /// Features that the client requests to be automatically enabled for its new session. + #[xml(element(n = ..))] pub payloads: Vec, } -impl TryFrom for BindQuery { - type Error = FromElementError; - - fn try_from(root: Element) -> Result { - check_self!(root, "bind", BIND2); - check_no_attributes!(root, "bind"); - - let mut tag = None; - let mut payloads = Vec::new(); - for child in root.children() { - if child.is("tag", ns::BIND2) { - if tag.is_some() { - return Err( - Error::Other("Bind must not have more than one tag element.").into(), - ); - } - check_no_attributes!(child, "tag"); - check_no_children!(child, "tag"); - tag = Some(child.text()); - } else { - payloads.push(child.clone()); - } - } - - Ok(BindQuery { tag, payloads }) - } -} - -impl From for Element { - fn from(bind: BindQuery) -> Element { - Element::builder("bind", ns::BIND2) - .append_all( - bind.tag - .map(|tag| Element::builder("tag", ns::BIND2).append(tag)), - ) - .append_all(bind.payloads) - .build() - } -} - /// Represents a `` element, which tells the client its resource is bound, alongside other /// requests. -#[derive(Debug, Clone, PartialEq)] +#[derive(FromXml, AsXml, Debug, Clone, PartialEq)] +#[xml(namespace = ns::BIND2, name = "bound")] pub struct Bound { /// Indicates which messages got missed by this particular device, start is the oldest message /// and end is the newest, before this connection. + #[xml(child(default))] pub mam_metadata: Option, /// Additional payloads which happened during the binding process. + #[xml(element(n = ..))] pub payloads: Vec, } -impl TryFrom for Bound { - type Error = FromElementError; - - fn try_from(root: Element) -> Result { - check_self!(root, "bound", BIND2); - check_no_attributes!(root, "bound"); - - let mut mam_metadata = None; - let mut payloads = Vec::new(); - for child in root.children() { - if child.is("metadata", ns::MAM) { - if mam_metadata.is_some() { - return Err( - Error::Other("Bind must not have more than one metadata element.").into(), - ); - } - mam_metadata = Some(mam::MetadataResponse::try_from(child.clone())?); - } else { - payloads.push(child.clone()); - } - } - - Ok(Bound { - mam_metadata, - payloads, - }) - } -} - -impl From for Element { - fn from(bound: Bound) -> Element { - Element::builder("bound", ns::BIND2) - .append_all(bound.mam_metadata) - .build() - } -} - #[cfg(test)] mod tests { use super::*; @@ -143,6 +71,14 @@ mod tests { assert_size!(Bound, 104); } + #[test] + fn test_empty() { + let elem: Element = "".parse().unwrap(); + let bind = BindQuery::try_from(elem).unwrap(); + assert_eq!(bind.tag, None); + assert_eq!(bind.payloads.len(), 0); + } + #[test] fn test_simple() { // Example 1