xmpp-parsers: Convert some more elements to xso

Emmanuel Gil Peyrot created

Change summary

parsers/src/bookmarks.rs       | 24 ++++++++++----------
parsers/src/fast.rs            | 18 ++++++++--------
parsers/src/jingle_ft.rs       | 36 ++++++++++++++++----------------
parsers/src/jingle_raw_udp.rs  | 17 +++++++--------
parsers/src/mam.rs             | 36 ++++++++++++++++----------------
parsers/src/muc/user.rs        | 40 ++++++++++++++++++-----------------
parsers/src/pubsub/pubsub.rs   | 31 ++++++++++++++-------------
parsers/src/stream_features.rs | 26 +++++++----------------
parsers/src/util/macros.rs     | 26 +++++++++++++++++++++++
9 files changed, 136 insertions(+), 118 deletions(-)

Detailed changes

parsers/src/bookmarks.rs 🔗

@@ -75,18 +75,18 @@ pub struct Url {
     pub url: String,
 }
 
-generate_element!(
-    /// Container element for multiple bookmarks.
-    #[derive(Default)]
-    Storage, "storage", BOOKMARKS,
-    children: [
-        /// Conferences the user has expressed an interest in.
-        conferences: Vec<Conference> = ("conference", BOOKMARKS) => Conference,
-
-        /// URLs the user is interested in.
-        urls: Vec<Url> = ("url", BOOKMARKS) => Url
-    ]
-);
+/// Container element for multiple bookmarks.
+#[derive(FromXml, AsXml, PartialEq, Debug, Clone, Default)]
+#[xml(namespace = ns::BOOKMARKS, name = "storage")]
+pub struct Storage {
+    /// Conferences the user has expressed an interest in.
+    #[xml(child(n = ..))]
+    pub conferences: Vec<Conference>,
+
+    /// URLs the user is interested in.
+    #[xml(child(n = ..))]
+    pub urls: Vec<Url>,
+}
 
 impl Storage {
     /// Create an empty bookmarks storage.

parsers/src/fast.rs 🔗

@@ -20,18 +20,18 @@ generate_attribute!(
     Tls0Rtt, "tls-0rtt", bool
 );
 
-generate_element!(
 /// This is the `<fast/>` element sent by the server as a SASL2 inline feature.
-FastQuery, "fast", FAST,
-attributes: [
+#[derive(FromXml, AsXml, Debug, Clone, PartialEq)]
+#[xml(namespace = ns::FAST, name = "fast")]
+pub struct FastQuery {
     /// Whether TLS zero-roundtrip is possible.
-    tls_0rtt: Default<Tls0Rtt> = "tls-0rtt",
-],
-children: [
+    #[xml(attribute(default, name = "tls-0rtt"))]
+    pub tls_0rtt: Tls0Rtt,
+
     /// A list of `<mechanism/>` elements, listing all server allowed mechanisms.
-    mechanisms: Vec<Mechanism> = ("mechanism", FAST) => Mechanism
-]
-);
+    #[xml(child(n = ..))]
+    pub mechanisms: Vec<Mechanism>,
+}
 
 /// This is the `<fast/>` element the client MUST include within its SASL2 authentication request.
 #[derive(FromXml, AsXml, Debug, Clone, PartialEq)]

parsers/src/jingle_ft.rs 🔗

@@ -16,23 +16,23 @@ use xso::{
     AsXml, FromXml,
 };
 
-generate_element!(
-    /// Represents a range in a file.
-    #[derive(Default)]
-    Range, "range", JINGLE_FT,
-    attributes: [
-        /// The offset in bytes from the beginning of the file.
-        offset: Default<u64> = "offset",
-
-        /// The length in bytes of the range, or None to be the entire
-        /// remaining of the file.
-        length: Option<u64> = "length"
-    ],
-    children: [
-        /// List of hashes for this range.
-        hashes: Vec<Hash> = ("hash", HASHES) => Hash
-    ]
-);
+/// Represents a range in a file.
+#[derive(FromXml, AsXml, PartialEq, Debug, Clone, Default)]
+#[xml(namespace = ns::JINGLE_FT, name = "range")]
+pub struct Range {
+    /// The offset in bytes from the beginning of the file.
+    #[xml(attribute(default))]
+    pub offset: u64,
+
+    /// The length in bytes of the range, or None to be the entire
+    /// remaining of the file.
+    #[xml(attribute(default))]
+    pub length: Option<u64>,
+
+    /// List of hashes for this range.
+    #[xml(child(n = ..))]
+    pub hashes: Vec<Hash>,
+}
 
 impl Range {
     /// Creates a new range.
@@ -632,6 +632,6 @@ mod tests {
             FromElementError::Invalid(Error::Other(string)) => string,
             _ => panic!(),
         };
-        assert_eq!(message, "Unknown attribute in range element.");
+        assert_eq!(message, "Unknown attribute in Range element.");
     }
 }

parsers/src/jingle_raw_udp.rs 🔗

@@ -11,15 +11,14 @@ use xso::{AsXml, FromXml};
 use crate::jingle_ice_udp::Type;
 use crate::ns;
 
-generate_element!(
-    /// Wrapper element for an raw UDP transport.
-    #[derive(Default)]
-    Transport, "transport", JINGLE_RAW_UDP,
-    children: [
-        /// List of candidates for this raw UDP session.
-        candidates: Vec<Candidate> = ("candidate", JINGLE_RAW_UDP) => Candidate
-    ]
-);
+/// Wrapper element for an raw UDP transport.
+#[derive(FromXml, AsXml, PartialEq, Debug, Clone, Default)]
+#[xml(namespace = ns::JINGLE_RAW_UDP, name = "transport")]
+pub struct Transport {
+    /// List of candidates for this raw UDP session.
+    #[xml(child(n = ..))]
+    pub candidates: Vec<Candidate>,
+}
 
 impl Transport {
     /// Create a new ICE-UDP transport.

parsers/src/mam.rs 🔗

@@ -144,24 +144,24 @@ generate_attribute!(
     bool
 );
 
-generate_element!(
-    /// Notes the end of a page in a query.
-    Fin, "fin", MAM,
-    attributes: [
-        /// True when the end of a MAM query has been reached.
-        complete: Default<Complete> = "complete",
-    ],
-    children: [
-        /// Describes the current page, it should contain at least [first]
-        /// (with an [index]) and [last], and generally [count].
-        ///
-        /// [first]: ../rsm/struct.SetResult.html#structfield.first
-        /// [index]: ../rsm/struct.SetResult.html#structfield.first_index
-        /// [last]: ../rsm/struct.SetResult.html#structfield.last
-        /// [count]: ../rsm/struct.SetResult.html#structfield.count
-        set: Required<SetResult> = ("set", RSM) => SetResult
-    ]
-);
+/// Notes the end of a page in a query.
+#[derive(FromXml, AsXml, Debug, Clone, PartialEq)]
+#[xml(namespace = ns::MAM, name = "fin")]
+pub struct Fin {
+    /// True when the end of a MAM query has been reached.
+    #[xml(attribute(default))]
+    pub complete: Complete,
+
+    /// Describes the current page, it should contain at least [first]
+    /// (with an [index]) and [last], and generally [count].
+    ///
+    /// [first]: ../rsm/struct.SetResult.html#structfield.first
+    /// [index]: ../rsm/struct.SetResult.html#structfield.first_index
+    /// [last]: ../rsm/struct.SetResult.html#structfield.last
+    /// [count]: ../rsm/struct.SetResult.html#structfield.count
+    #[xml(child)]
+    pub set: SetResult,
+}
 
 impl IqResultPayload for Fin {}
 

parsers/src/muc/user.rs 🔗

@@ -219,31 +219,31 @@ generate_attribute!(
 pub struct Item {
     /// The affiliation of this user with the room.
     #[xml(attribute)]
-    affiliation: Affiliation,
+    pub affiliation: Affiliation,
 
     /// The real JID of this user, if you are allowed to see it.
     #[xml(attribute(default))]
-    jid: Option<FullJid>,
+    pub jid: Option<FullJid>,
 
     /// The current nickname of this user.
     #[xml(attribute(default))]
-    nick: Option<String>,
+    pub nick: Option<String>,
 
     /// The current role of this user.
     #[xml(attribute)]
-    role: Role,
+    pub role: Role,
 
     /// The actor affected by this item.
     #[xml(child(default))]
-    actor: Option<Actor>,
+    pub actor: Option<Actor>,
 
     /// Whether this continues a one-to-one discussion.
     #[xml(child(default))]
-    continue_: Option<Continue>,
+    pub continue_: Option<Continue>,
 
     /// A reason for this item.
     #[xml(child(default))]
-    reason: Option<Reason>,
+    pub reason: Option<Reason>,
 }
 
 impl Item {
@@ -293,16 +293,18 @@ impl Item {
     }
 }
 
-generate_element!(
-    /// The main muc#user element.
-    MucUser, "x", MUC_USER, children: [
-        /// List of statuses applying to this item.
-        status: Vec<Status> = ("status", MUC_USER) => Status,
-
-        /// List of items.
-        items: Vec<Item> = ("item", MUC_USER) => Item
-    ]
-);
+/// The main muc#user element.
+#[derive(FromXml, AsXml, Debug, PartialEq, Clone)]
+#[xml(namespace = ns::MUC_USER, name = "x")]
+pub struct MucUser {
+    /// List of statuses applying to this item.
+    #[xml(child(n = ..))]
+    pub status: Vec<Status>,
+
+    /// List of items.
+    #[xml(child(n = ..))]
+    pub items: Vec<Item>,
+}
 
 impl Default for MucUser {
     fn default() -> Self {
@@ -380,7 +382,7 @@ mod tests {
             FromElementError::Invalid(Error::Other(string)) => string,
             _ => panic!(),
         };
-        assert_eq!(message, "Unknown child in x element.");
+        assert_eq!(message, "Unknown child in MucUser element.");
     }
 
     #[test]
@@ -407,7 +409,7 @@ mod tests {
             FromElementError::Invalid(Error::Other(string)) => string,
             _ => panic!(),
         };
-        assert_eq!(message, "Unknown attribute in x element.");
+        assert_eq!(message, "Unknown attribute in MucUser element.");
     }
 
     #[test]

parsers/src/pubsub/pubsub.rs 🔗

@@ -167,21 +167,22 @@ generate_attribute!(
     bool
 );
 
-generate_element!(
-    /// A request to retract some items from a node.
-    Retract, "retract", PUBSUB,
-    attributes: [
-        /// The node affected by this request.
-        node: Required<NodeName> = "node",
-
-        /// Whether a retract request should notify subscribers or not.
-        notify: Default<Notify> = "notify",
-    ],
-    children: [
-        /// The items affected by this request.
-        items: Vec<Item> = ("item", PUBSUB) => Item
-    ]
-);
+/// A request to retract some items from a node.
+#[derive(FromXml, AsXml, Debug, PartialEq, Clone)]
+#[xml(namespace = ns::PUBSUB, name = "retract")]
+pub struct Retract {
+    /// The node affected by this request.
+    #[xml(attribute)]
+    pub node: NodeName,
+
+    /// Whether a retract request should notify subscribers or not.
+    #[xml(attribute(default))]
+    pub notify: Notify,
+
+    /// The items affected by this request.
+    #[xml(child(n = ..))]
+    pub items: Vec<Item>,
+}
 
 /// Indicate that the subscription can be configured.
 #[derive(Debug, Clone, PartialEq)]

parsers/src/stream_features.rs 🔗

@@ -45,24 +45,14 @@ pub struct RequiredStartTls;
 #[xml(namespace = ns::BIND, name = "bind")]
 pub struct Bind;
 
-generate_element!(
-    /// List of supported SASL mechanisms
-    #[derive(Default)]
-    SaslMechanisms, "mechanisms", SASL,
-    children: [
-        /// List of information elements describing this avatar.
-        mechanisms: Vec<SaslMechanism> = ("mechanism", SASL) => SaslMechanism,
-    ]
-);
-
-// TODO: Uncomment me when xso supports collections, see
-// https://gitlab.com/xmpp-rs/xmpp-rs/-/issues/136
-// #[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
-// #[xml(namespace = ns::SASL, name = "mechanisms")]
-// pub struct SaslMechanisms {
-//     #[xml(child(default))]
-//     mechanisms: Vec<SaslMechanism>,
-// }
+/// List of supported SASL mechanisms
+#[derive(FromXml, AsXml, PartialEq, Debug, Clone, Default)]
+#[xml(namespace = ns::SASL, name = "mechanisms")]
+pub struct SaslMechanisms {
+    /// List of information elements describing this avatar.
+    #[xml(child(n = ..))]
+    pub mechanisms: Vec<SaslMechanism>,
+}
 
 /// The name of a SASL mechanism.
 #[derive(FromXml, AsXml, PartialEq, Debug, Clone)]

parsers/src/util/macros.rs 🔗

@@ -300,6 +300,24 @@ macro_rules! generate_attribute_enum {
                 })
             }
         }
+
+        impl ::xso::FromXml for $elem {
+            type Builder = ::xso::minidom_compat::FromEventsViaElement<$elem>;
+
+            fn from_events(
+                qname: ::xso::exports::rxml::QName,
+                attrs: ::xso::exports::rxml::AttrMap,
+            ) -> Result<Self::Builder, ::xso::error::FromEventsError> {
+                if qname.0 != crate::ns::$ns || qname.1 != $name {
+                    return Err(::xso::error::FromEventsError::Mismatch {
+                        name: qname,
+                        attrs,
+                    })
+                }
+                Self::Builder::new(qname, attrs)
+            }
+        }
+
         impl From<$elem> for minidom::Element {
             fn from(elem: $elem) -> minidom::Element {
                 minidom::Element::builder($name, crate::ns::$ns)
@@ -309,6 +327,14 @@ macro_rules! generate_attribute_enum {
                      .build()
             }
         }
+
+        impl ::xso::AsXml for $elem {
+            type ItemIter<'x> = ::xso::minidom_compat::AsItemsViaElement<'x>;
+
+            fn as_xml_iter(&self) -> Result<Self::ItemIter<'_>, ::xso::error::Error> {
+                ::xso::minidom_compat::AsItemsViaElement::new(self.clone())
+            }
+        }
     );
 }