From 2b346c4e87999d65f37c03a816f04f1fa7e9b9d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Sch=C3=A4fer?= Date: Sat, 3 Aug 2024 13:04:56 +0200 Subject: [PATCH] parsers: port more things to derive macros --- parsers/src/avatar.rs | 16 ++--- parsers/src/cert_management.rs | 32 +++++----- parsers/src/disco.rs | 39 ++++++------ parsers/src/ecaps2.rs | 24 ++++---- parsers/src/extdisco.rs | 42 ++++++------- parsers/src/http_upload.rs | 51 +++++++++++----- parsers/src/jingle_grouping.rs | 24 ++++---- parsers/src/jingle_ssma.rs | 48 +++++++-------- parsers/src/legacy_omemo.rs | 65 ++++++++++---------- parsers/src/media_element.rs | 33 +++++----- parsers/src/mix.rs | 30 ++++----- parsers/src/openpgp.rs | 16 ++--- parsers/src/pubsub/owner.rs | 48 +++++++-------- parsers/src/pubsub/pubsub.rs | 108 +++++++++++++++++---------------- parsers/src/reactions.rs | 24 ++++---- parsers/src/roster.rs | 42 +++++++------ parsers/src/rsm.rs | 22 +++++++ parsers/src/util/macros.rs | 22 +++++++ 18 files changed, 382 insertions(+), 304 deletions(-) diff --git a/parsers/src/avatar.rs b/parsers/src/avatar.rs index 21780dbac334f252084d924b1f453579ab36118b..3d8925fba267585c4f2bb9a388300cc3415516f6 100644 --- a/parsers/src/avatar.rs +++ b/parsers/src/avatar.rs @@ -13,14 +13,14 @@ use crate::hashes::Sha1HexAttribute; use crate::ns; use crate::pubsub::PubSubPayload; -generate_element!( - /// Communicates information about an avatar. - Metadata, "metadata", AVATAR_METADATA, - children: [ - /// List of information elements describing this avatar. - infos: Vec = ("info", AVATAR_METADATA) => Info - ] -); +/// Communicates information about an avatar. +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] +#[xml(namespace = ns::AVATAR_METADATA, name = "metadata")] +pub struct Metadata { + /// List of information elements describing this avatar. + #[xml(child(n = ..))] + pub infos: Vec, +} impl PubSubPayload for Metadata {} diff --git a/parsers/src/cert_management.rs b/parsers/src/cert_management.rs index 9d15c4830eea5bbae62ffba617d311927a32b8fb..33d8c223dc670d33e0ed0edef79596c17a14c231 100644 --- a/parsers/src/cert_management.rs +++ b/parsers/src/cert_management.rs @@ -56,14 +56,14 @@ generate_elem_id!( SASL_CERT ); -generate_element!( - /// A list of resources currently using this certificate. - Users, "users", SASL_CERT, - children: [ - /// Resources currently using this certificate. - resources: Vec = ("resource", SASL_CERT) => Resource - ] -); +/// A list of resources currently using this certificate. +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] +#[xml(namespace = ns::SASL_CERT, name = "users")] +pub struct Users { + /// Resources currently using this certificate. + #[xml(child(n = ..))] + pub resources: Vec, +} generate_element!( /// An X.509 certificate being set for this user. @@ -83,14 +83,14 @@ generate_element!( ] ); -generate_element!( - /// Server answers with the current list of X.509 certificates. - ListCertsResponse, "items", SASL_CERT, - children: [ - /// List of certificates. - items: Vec = ("item", SASL_CERT) => Item - ] -); +/// Server answers with the current list of X.509 certificates. +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] +#[xml(namespace = ns::SASL_CERT, name = "items")] +pub struct ListCertsResponse { + /// List of certificates. + #[xml(child(n = ..))] + pub items: Vec, +} impl IqResultPayload for ListCertsResponse {} diff --git a/parsers/src/disco.rs b/parsers/src/disco.rs index 8540e12af9ab0226e649d4e98d6f413125b7161b..16a3b9cb98f0705493c9d5012a44c83bb6098738 100644 --- a/parsers/src/disco.rs +++ b/parsers/src/disco.rs @@ -220,25 +220,26 @@ pub struct Item { pub name: Option, } -generate_element!( - /// Structure representing a `` element. - /// - /// It should only be used in an ``, as it can only - /// represent the result, and not a request. - DiscoItemsResult, "query", DISCO_ITEMS, - attributes: [ - /// Node on which we have done this discovery. - node: Option = "node" - ], - children: [ - /// List of items pointed by this entity. - items: Vec = ("item", DISCO_ITEMS) => Item, - - /// Optional paging via Result Set Management - rsm: Option = ("set", RSM) => SetResult, - ] -); +/// Structure representing a `` element. +/// +/// It should only be used in an ``, as it can only +/// represent the result, and not a request. +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] +#[xml(namespace = ns::DISCO_ITEMS, name = "query")] +pub struct DiscoItemsResult { + /// Node on which we have done this discovery. + #[xml(attribute(default))] + pub node: Option, + + /// List of items pointed by this entity. + #[xml(child(n = ..))] + pub items: Vec, + + /// Optional paging via Result Set Management + #[xml(child(default))] + pub rsm: Option, +} impl IqResultPayload for DiscoItemsResult {} diff --git a/parsers/src/ecaps2.rs b/parsers/src/ecaps2.rs index 6472e0ff0037d64a8a5d5635d35289f58def50d2..ac85f8a5d699c9ae8127cdd8d88dc849e71bd648 100644 --- a/parsers/src/ecaps2.rs +++ b/parsers/src/ecaps2.rs @@ -4,6 +4,8 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use xso::{AsXml, FromXml}; + use crate::data_forms::DataForm; use crate::disco::{DiscoInfoQuery, DiscoInfoResult, Feature, Identity}; use crate::hashes::{Algo, Hash}; @@ -16,16 +18,16 @@ use sha2::{Sha256, Sha512}; use sha3::{Sha3_256, Sha3_512}; use xso::error::Error; -generate_element!( - /// Represents a set of capability hashes, all of them must correspond to - /// the same input [disco#info](../disco/struct.DiscoInfoResult.html), - /// using different [algorithms](../hashes/enum.Algo.html). - ECaps2, "c", ECAPS2, - children: [ - /// Hashes of the [disco#info](../disco/struct.DiscoInfoResult.html). - hashes: Vec = ("hash", HASHES) => Hash - ] -); +/// Represents a set of capability hashes, all of them must correspond to +/// the same input [disco#info](../disco/struct.DiscoInfoResult.html), +/// using different [algorithms](../hashes/enum.Algo.html). +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] +#[xml(namespace = ns::ECAPS2, name = "c")] +pub struct ECaps2 { + /// Hashes of the [disco#info](../disco/struct.DiscoInfoResult.html). + #[xml(child(n = ..))] + pub hashes: Vec, +} impl PresencePayload for ECaps2 {} @@ -230,7 +232,7 @@ mod tests { FromElementError::Invalid(Error::Other(string)) => string, _ => panic!(), }; - assert_eq!(message, "Unknown child in c element."); + assert_eq!(message, "Unknown child in ECaps2 element."); } #[test] diff --git a/parsers/src/extdisco.rs b/parsers/src/extdisco.rs index 89991517112cd73e69a6a2c23e48ed0d59604365..9a9626e0ff3e077f61fa04b40c4483abc860e3b1 100644 --- a/parsers/src/extdisco.rs +++ b/parsers/src/extdisco.rs @@ -104,37 +104,37 @@ impl IqGetPayload for Service {} #[derive(FromXml, AsXml, PartialEq, Debug, Clone)] #[xml(namespace = ns::EXT_DISCO, name = "services")] pub struct ServicesQuery { - /// TODO + /// The type of service to filter for. #[xml(attribute(default, name = "type"))] pub type_: Option, } impl IqGetPayload for ServicesQuery {} -generate_element!( - /// Structure representing a `` element. - ServicesResult, "services", EXT_DISCO, - attributes: [ - /// TODO - type_: Option = "type", - ], - children: [ - /// List of services. - services: Vec = ("service", EXT_DISCO) => Service - ] -); +/// Structure representing a `` element. +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] +#[xml(namespace = ns::EXT_DISCO, name = "services")] +pub struct ServicesResult { + /// The service type which was requested. + #[xml(attribute(name = "type", default))] + pub type_: Option, + + /// List of services. + #[xml(child(n = ..))] + pub services: Vec, +} impl IqResultPayload for ServicesResult {} impl IqSetPayload for ServicesResult {} -generate_element!( - /// Structure representing a `` element. - Credentials, "credentials", EXT_DISCO, - children: [ - /// List of services. - services: Vec = ("service", EXT_DISCO) => Service - ] -); +/// Structure representing a `` element. +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] +#[xml(namespace = ns::EXT_DISCO, name = "credentials")] +pub struct Credentials { + /// List of services. + #[xml(child(n = ..))] + pub services: Vec, +} impl IqGetPayload for Credentials {} impl IqResultPayload for Credentials {} diff --git a/parsers/src/http_upload.rs b/parsers/src/http_upload.rs index c795c7438f8f79dbdc1d5d3bdbcbf0f97f7981b4..35c691828e8936029a919b9ce277c848a035c976 100644 --- a/parsers/src/http_upload.rs +++ b/parsers/src/http_upload.rs @@ -5,8 +5,9 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. use xso::{ - error::{Error, FromElementError}, - AsXml, FromXml, + error::{Error, FromElementError, FromEventsError}, + exports::rxml, + minidom_compat, AsXml, FromXml, }; use crate::iq::{IqGetPayload, IqResultPayload}; @@ -68,6 +69,20 @@ impl TryFrom for Header { } } +impl FromXml for Header { + type Builder = minidom_compat::FromEventsViaElement
; + + fn from_events( + qname: rxml::QName, + attrs: rxml::AttrMap, + ) -> Result { + if qname.0 != ns::HTTP_UPLOAD || qname.1 != "header" { + return Err(FromEventsError::Mismatch { name: qname, attrs }); + } + Self::Builder::new(qname, attrs) + } +} + impl From
for Element { fn from(elem: Header) -> Element { let (attr, val) = match elem { @@ -83,18 +98,26 @@ impl From
for Element { } } -generate_element!( - /// Put URL - Put, "put", HTTP_UPLOAD, - attributes: [ - /// URL - url: Required = "url", - ], - children: [ - /// Header list - headers: Vec
= ("header", HTTP_UPLOAD) => Header - ] -); +impl AsXml for Header { + type ItemIter<'x> = minidom_compat::AsItemsViaElement<'x>; + + fn as_xml_iter(&self) -> Result, Error> { + minidom_compat::AsItemsViaElement::new(self.clone()) + } +} + +/// Put URL +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] +#[xml(namespace = ns::HTTP_UPLOAD, name = "put")] +pub struct Put { + /// URL + #[xml(attribute)] + pub url: String, + + /// Header list + #[xml(child(n = ..))] + pub headers: Vec
, +} /// Get URL #[derive(FromXml, AsXml, PartialEq, Debug, Clone)] diff --git a/parsers/src/jingle_grouping.rs b/parsers/src/jingle_grouping.rs index ed67092fae8816ea27927842eb6841ef3b1a522c..1d4389345e4c878e0b1ea763da9465101f3332d3 100644 --- a/parsers/src/jingle_grouping.rs +++ b/parsers/src/jingle_grouping.rs @@ -38,18 +38,18 @@ impl Content { } } -generate_element!( - /// A semantic group of contents. - Group, "group", JINGLE_GROUPING, - attributes: [ - /// Semantics of the grouping. - semantics: Required = "semantics", - ], - children: [ - /// List of contents that should be grouped with each other. - contents: Vec = ("content", JINGLE_GROUPING) => Content - ] -); +/// A semantic group of contents. +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] +#[xml(namespace = ns::JINGLE_GROUPING, name = "group")] +pub struct Group { + /// Semantics of the grouping. + #[xml(attribute)] + pub semantics: Semantics, + + /// List of contents that should be grouped with each other. + #[xml(child(n = ..))] + pub contents: Vec, +} #[cfg(test)] mod tests { diff --git a/parsers/src/jingle_ssma.rs b/parsers/src/jingle_ssma.rs index 2ea691888407afe268e359e13198d05f624d4ab6..cd6701d3545f342e1d98c23e4a3ebd4785774061 100644 --- a/parsers/src/jingle_ssma.rs +++ b/parsers/src/jingle_ssma.rs @@ -8,18 +8,18 @@ use xso::{AsXml, FromXml}; use crate::ns; -generate_element!( - /// Source element for the ssrc SDP attribute. - Source, "source", JINGLE_SSMA, - attributes: [ - /// Maps to the ssrc-id parameter. - id: Required = "ssrc", - ], - children: [ - /// List of attributes for this source. - parameters: Vec = ("parameter", JINGLE_SSMA) => Parameter - ] -); +/// Source element for the ssrc SDP attribute. +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] +#[xml(namespace = ns::JINGLE_SSMA, name = "source")] +pub struct Source { + /// Maps to the ssrc-id parameter. + #[xml(attribute = "ssrc")] + pub id: u32, + + /// List of attributes for this source. + #[xml(child(n = ..))] + pub parameters: Vec, +} impl Source { /// Create a new SSMA Source element. @@ -67,18 +67,18 @@ generate_attribute!( } ); -generate_element!( - /// Element grouping multiple ssrc. - Group, "ssrc-group", JINGLE_SSMA, - attributes: [ - /// The semantics of this group. - semantics: Required = "semantics", - ], - children: [ - /// The various ssrc concerned by this group. - sources: Vec = ("source", JINGLE_SSMA) => Source - ] -); +/// Element grouping multiple ssrc. +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] +#[xml(namespace = ns::JINGLE_SSMA, name = "ssrc-group")] +pub struct Group { + /// The semantics of this group. + #[xml(attribute)] + pub semantics: Semantics, + + /// The various ssrc concerned by this group. + #[xml(child(n = ..))] + pub sources: Vec, +} #[cfg(test)] mod tests { diff --git a/parsers/src/legacy_omemo.rs b/parsers/src/legacy_omemo.rs index 278da5169c5a74f54d245f808fa2e5a57e46f3b8..56bd7d6ebc505016b6e24e731a0fa89c07967f83 100644 --- a/parsers/src/legacy_omemo.rs +++ b/parsers/src/legacy_omemo.rs @@ -19,15 +19,15 @@ pub struct Device { pub id: u32, } -generate_element!( - /// A user's device list contains the OMEMO device ids of all the user's - /// devicse. These can be used to look up bundles and build a session. - DeviceList, "list", LEGACY_OMEMO, - children: [ - /// List of devices - devices: Vec = ("device", LEGACY_OMEMO) => Device - ] -); +/// A user's device list contains the OMEMO device ids of all the user's +/// devicse. These can be used to look up bundles and build a session. +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] +#[xml(namespace = ns::LEGACY_OMEMO, name = "list")] +pub struct DeviceList { + /// List of devices + #[xml(child(n = ..))] + pub devices: Vec, +} impl PubSubPayload for DeviceList {} @@ -64,15 +64,15 @@ pub struct IdentityKey { pub data: Vec, } -generate_element!( +/// List of (single use) PreKeys +/// Part of a device's bundle +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] +#[xml(namespace = ns::LEGACY_OMEMO, name = "prekeys")] +pub struct Prekeys { /// List of (single use) PreKeys - /// Part of a device's bundle - Prekeys, "prekeys", LEGACY_OMEMO, - children: [ - /// List of (single use) PreKeys - keys: Vec = ("preKeyPublic", LEGACY_OMEMO) => PreKeyPublic, - ] -); + #[xml(child(n = ..))] + pub keys: Vec, +} /// PreKey public key /// Part of a device's bundle @@ -113,22 +113,23 @@ pub struct Bundle { impl PubSubPayload for Bundle {} -generate_element!( - /// The header contains encrypted keys for a message - Header, "header", LEGACY_OMEMO, - attributes: [ - /// The device id of the sender - sid: Required = "sid", - ], - children: [ - /// The key that the payload message is encrypted with, separately - /// encrypted for each recipient device. - keys: Vec = ("key", LEGACY_OMEMO) => Key, +/// The header contains encrypted keys for a message +#[derive(FromXml, AsXml, Debug, PartialEq, Clone)] +#[xml(namespace = ns::LEGACY_OMEMO, name = "header")] +pub struct Header { + /// The device id of the sender + #[xml(attribute)] + pub sid: u32, - /// IV used for payload encryption - iv: Required = ("iv", LEGACY_OMEMO) => IV - ] -); + /// The key that the payload message is encrypted with, separately + /// encrypted for each recipient device. + #[xml(child(n = ..))] + pub keys: Vec, + + /// IV used for payload encryption + #[xml(child)] + pub iv: IV, +} /// IV used for payload encryption #[derive(FromXml, AsXml, PartialEq, Debug, Clone)] diff --git a/parsers/src/media_element.rs b/parsers/src/media_element.rs index 973d5f49385e0f69acb13c1432ba5301884a2b71..5607aad6449e347c41b7c2665926c2294d422218 100644 --- a/parsers/src/media_element.rs +++ b/parsers/src/media_element.rs @@ -27,22 +27,23 @@ pub struct Uri { pub uri: String, } -generate_element!( - /// References a media element, to be used in [data - /// forms](../data_forms/index.html). - MediaElement, "media", MEDIA_ELEMENT, - attributes: [ - /// The recommended display width in pixels. - width: Option = "width", +/// References a media element, to be used in [data +/// forms](../data_forms/index.html). +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] +#[xml(namespace = ns::MEDIA_ELEMENT, name = "media")] +pub struct MediaElement { + /// The recommended display width in pixels. + #[xml(attribute(default))] + pub width: Option, + + /// The recommended display height in pixels. + #[xml(attribute(default))] + pub height: Option, - /// The recommended display height in pixels. - height: Option = "height" - ], - children: [ - /// A list of URIs referencing this media. - uris: Vec = ("uri", MEDIA_ELEMENT) => Uri - ] -); + /// A list of URIs referencing this media. + #[xml(child(n = ..))] + pub uris: Vec, +} #[cfg(test)] mod tests { @@ -162,7 +163,7 @@ mod tests { FromElementError::Invalid(Error::Other(string)) => string, _ => panic!(), }; - assert_eq!(message, "Unknown child in media element."); + assert_eq!(message, "Unknown child in MediaElement element."); } #[test] diff --git a/parsers/src/mix.rs b/parsers/src/mix.rs index 7835a5dbb7d8e4a392acc6ed746a58843f5aec3b..bb6704f00da1bd88ded72aded92e131f767b9e10 100644 --- a/parsers/src/mix.rs +++ b/parsers/src/mix.rs @@ -113,21 +113,21 @@ impl Join { } } -generate_element!( - /// Update a given subscription. - UpdateSubscription, "update-subscription", MIX_CORE, - attributes: [ - /// The JID of the user to be affected. - // TODO: why is it not a participant id instead? - jid: Option = "jid", - ], - children: [ - /// The list of additional nodes to subscribe to. - // TODO: what happens when we are already subscribed? Also, how do we unsubscribe from - // just one? - subscribes: Vec = ("subscribe", MIX_CORE) => Subscribe - ] -); +/// Update a given subscription. +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] +#[xml(namespace = ns::MIX_CORE, name = "update-subscription")] +pub struct UpdateSubscription { + /// The JID of the user to be affected. + // TODO: why is it not a participant id instead? + #[xml(attribute(default))] + pub jid: Option, + + /// The list of additional nodes to subscribe to. + // TODO: what happens when we are already subscribed? Also, how do we unsubscribe from + // just one? + #[xml(child(n = ..))] + pub subscribes: Vec, +} impl IqSetPayload for UpdateSubscription {} impl IqResultPayload for UpdateSubscription {} diff --git a/parsers/src/openpgp.rs b/parsers/src/openpgp.rs index 3ff55d878bd9eadecdd325a4a017b635a134c622..09c3b633f4374a2c097ea861dabbf8d6e97f59e9 100644 --- a/parsers/src/openpgp.rs +++ b/parsers/src/openpgp.rs @@ -48,14 +48,14 @@ pub struct PubKeyMeta { pub date: DateTime, } -generate_element!( - /// List of public key metadata - PubKeysMeta, "public-key-list", OX, - children: [ - /// Public keys - pubkeys: Vec = ("pubkey-metadata", OX) => PubKeyMeta - ] -); +/// List of public key metadata +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] +#[xml(namespace = ns::OX, name = "public-key-list")] +pub struct PubKeysMeta { + /// Public keys + #[xml(child(n = ..))] + pub pubkeys: Vec, +} impl PubSubPayload for PubKeysMeta {} diff --git a/parsers/src/pubsub/owner.rs b/parsers/src/pubsub/owner.rs index 94d49c4e49a397a57dfa0ca4b4bb4f8b8de244f5..bc6ec3a6c40303180661c4bb873ae2fb6e766977 100644 --- a/parsers/src/pubsub/owner.rs +++ b/parsers/src/pubsub/owner.rs @@ -15,18 +15,18 @@ use jid::Jid; use minidom::Element; use xso::error::{Error, FromElementError}; -generate_element!( - /// A list of affiliations you have on a service, or on a node. - Affiliations, "affiliations", PUBSUB_OWNER, - attributes: [ - /// The node name this request pertains to. - node: Required = "node", - ], - children: [ - /// The actual list of affiliation elements. - affiliations: Vec = ("affiliation", PUBSUB_OWNER) => Affiliation - ] -); +/// A list of affiliations you have on a service, or on a node. +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] +#[xml(namespace = ns::PUBSUB_OWNER, name = "affiliations")] +pub struct Affiliations { + /// The node name this request pertains to. + #[xml(attribute)] + pub node: NodeName, + + /// The actual list of affiliation elements. + #[xml(child(n = ..))] + pub affiliations: Vec, +} /// An affiliation element. #[derive(FromXml, AsXml, PartialEq, Debug, Clone)] @@ -94,18 +94,18 @@ pub struct Purge { pub node: NodeName, } -generate_element!( - /// A request for current subscriptions. - Subscriptions, "subscriptions", PUBSUB_OWNER, - attributes: [ - /// The node to query. - node: Required = "node", - ], - children: [ - /// The list of subscription elements returned. - subscriptions: Vec = ("subscription", PUBSUB_OWNER) => SubscriptionElem - ] -); +/// A request for current subscriptions. +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] +#[xml(namespace = ns::PUBSUB_OWNER, name = "subscriptions")] +pub struct Subscriptions { + /// The node to query. + #[xml(attribute)] + pub node: NodeName, + + /// The list of subscription elements returned. + #[xml(child(n = ..))] + pub subscriptions: Vec, +} /// A subscription element, describing the state of a subscription. #[derive(FromXml, AsXml, PartialEq, Debug, Clone)] diff --git a/parsers/src/pubsub/pubsub.rs b/parsers/src/pubsub/pubsub.rs index 4a4167d9efaf9f85d3fe66e3f13e7d885b26120b..86bce5c9f15acbbaea3d69722aaa6f5cc00002a3 100644 --- a/parsers/src/pubsub/pubsub.rs +++ b/parsers/src/pubsub/pubsub.rs @@ -21,18 +21,18 @@ use minidom::Element; // TODO: a better solution would be to split this into a query and a result elements, like for // XEP-0030. -generate_element!( - /// A list of affiliations you have on a service, or on a node. - Affiliations, "affiliations", PUBSUB, - attributes: [ - /// The optional node name this request pertains to. - node: Option = "node", - ], - children: [ - /// The actual list of affiliation elements. - affiliations: Vec = ("affiliation", PUBSUB) => Affiliation - ] -); +/// A list of affiliations you have on a service, or on a node. +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] +#[xml(namespace = ns::PUBSUB, name = "affiliations")] +pub struct Affiliations { + /// The optional node name this request pertains to. + #[xml(attribute(default))] + pub node: Option, + + /// The actual list of affiliation elements. + #[xml(child(n = ..))] + pub affiliations: Vec, +} /// An affiliation element. #[derive(FromXml, AsXml, PartialEq, Debug, Clone)] @@ -77,25 +77,27 @@ pub struct Default { // type_: Option, } -generate_element!( - /// A request for a list of items. - Items, "items", PUBSUB, - attributes: [ - // TODO: should be an xs:positiveInteger, that is, an unbounded int ≥ 1. - /// Maximum number of items returned. - max_items: Option = "max_items", +/// A request for a list of items. +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] +#[xml(namespace = ns::PUBSUB, name = "items")] +pub struct Items { + // TODO: should be an xs:positiveInteger, that is, an unbounded int ≥ 1. + /// Maximum number of items returned. + #[xml(attribute(name = "max_items" /*sic!*/, default))] + pub max_items: Option, + + /// The node queried by this request. + #[xml(attribute)] + pub node: NodeName, - /// The node queried by this request. - node: Required = "node", + /// The subscription identifier related to this request. + #[xml(attribute(default))] + pub subid: Option, - /// The subscription identifier related to this request. - subid: Option = "subid", - ], - children: [ - /// The actual list of items returned. - items: Vec = ("item", PUBSUB) => Item - ] -); + /// The actual list of items returned. + #[xml(child(n = ..))] + pub items: Vec, +} impl Items { /// Create a new items request. @@ -136,18 +138,18 @@ pub struct Options { pub form: Option, } -generate_element!( - /// Request to publish items to a node. - Publish, "publish", PUBSUB, - attributes: [ - /// The target node for this operation. - node: Required = "node", - ], - children: [ - /// The items you want to publish. - items: Vec = ("item", PUBSUB) => Item - ] -); +/// Request to publish items to a node. +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] +#[xml(namespace = ns::PUBSUB, name = "publish")] +pub struct Publish { + /// The target node for this operation. + #[xml(attribute)] + pub node: NodeName, + + /// The items you want to publish. + #[xml(child(n = ..))] + pub items: Vec, +} /// The options associated to a publish request. #[derive(FromXml, AsXml, Debug, PartialEq, Clone)] @@ -259,18 +261,18 @@ pub struct Subscribe { pub node: Option, } -generate_element!( - /// A request for current subscriptions. - Subscriptions, "subscriptions", PUBSUB, - attributes: [ - /// The node to query. - node: Option = "node", - ], - children: [ - /// The list of subscription elements returned. - subscription: Vec = ("subscription", PUBSUB) => SubscriptionElem - ] -); +/// A request for current subscriptions. +#[derive(FromXml, AsXml, Debug, PartialEq, Clone)] +#[xml(namespace = ns::PUBSUB, name = "subscriptions")] +pub struct Subscriptions { + /// The node to query. + #[xml(attribute(default))] + pub node: Option, + + /// The list of subscription elements returned. + #[xml(child(n = ..))] + pub subscription: Vec, +} /// A subscription element, describing the state of a subscription. #[derive(FromXml, AsXml, Debug, PartialEq, Clone)] diff --git a/parsers/src/reactions.rs b/parsers/src/reactions.rs index b79afdda5b6406d358ed7c2e6ace7d79ca9e8689..80c419133bbe25103e6d4b4d395472aa8bda9ce0 100644 --- a/parsers/src/reactions.rs +++ b/parsers/src/reactions.rs @@ -9,18 +9,18 @@ use xso::{AsXml, FromXml}; use crate::message::MessagePayload; use crate::ns; -generate_element!( - /// Container for a set of reactions. - Reactions, "reactions", REACTIONS, - attributes: [ - /// The id of the message these reactions apply to. - id: Required = "id", - ], - children: [ - /// The list of reactions. - reactions: Vec = ("reaction", REACTIONS) => Reaction, - ] -); +/// Container for a set of reactions. +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] +#[xml(namespace = ns::REACTIONS, name = "reactions")] +pub struct Reactions { + /// The id of the message these reactions apply to. + #[xml(attribute)] + pub id: String, + + /// The list of reactions. + #[xml(child(n = ..))] + pub reactions: Vec, +} impl MessagePayload for Reactions {} diff --git a/parsers/src/roster.rs b/parsers/src/roster.rs index 7ce3ad560ed832abf3dac0e2c3bbe1fe9d0c1727..df9298657c0a5a7fcaa0564acdbb1efba51f1864 100644 --- a/parsers/src/roster.rs +++ b/parsers/src/roster.rs @@ -4,9 +4,13 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use crate::iq::{IqGetPayload, IqResultPayload, IqSetPayload}; +use xso::{AsXml, FromXml}; + use jid::BareJid; +use crate::iq::{IqGetPayload, IqResultPayload, IqSetPayload}; +use crate::ns; + generate_elem_id!( /// Represents a group a contact is part of. Group, @@ -67,22 +71,22 @@ generate_element!( ] ); -generate_element!( - /// The contact list of the user. - Roster, "query", ROSTER, - attributes: [ - /// Version of the contact list. - /// - /// This is an opaque string that should only be sent back to the server on - /// a new connection, if this client is storing the contact list between - /// connections. - ver: Option = "ver" - ], - children: [ - /// List of the contacts of the user. - items: Vec = ("item", ROSTER) => Item - ] -); +/// The contact list of the user. +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] +#[xml(namespace = ns::ROSTER, name = "query")] +pub struct Roster { + /// Version of the contact list. + /// + /// This is an opaque string that should only be sent back to the server on + /// a new connection, if this client is storing the contact list between + /// connections. + #[xml(attribute(default))] + pub ver: Option, + + /// List of the contacts of the user. + #[xml(child(n = ..))] + pub items: Vec, +} impl IqGetPayload for Roster {} impl IqSetPayload for Roster {} @@ -273,7 +277,7 @@ mod tests { FromElementError::Invalid(Error::Other(string)) => string, _ => panic!(), }; - assert_eq!(message, "Unknown child in query element."); + assert_eq!(message, "Unknown child in Roster element."); let elem: Element = "" .parse() @@ -283,7 +287,7 @@ mod tests { FromElementError::Invalid(Error::Other(string)) => string, _ => panic!(), }; - assert_eq!(message, "Unknown attribute in query element."); + assert_eq!(message, "Unknown attribute in Roster element."); } #[test] diff --git a/parsers/src/rsm.rs b/parsers/src/rsm.rs index 51b06769d7ae36e188c7e7d56f0e1e3d483a78b6..a30a42f44fa5dea2e29a6eb1080be7dbbd2236c8 100644 --- a/parsers/src/rsm.rs +++ b/parsers/src/rsm.rs @@ -172,6 +172,20 @@ impl TryFrom for SetResult { } } +impl FromXml for SetResult { + type Builder = minidom_compat::FromEventsViaElement; + + fn from_events( + qname: rxml::QName, + attrs: rxml::AttrMap, + ) -> Result { + if qname.0 != crate::ns::RSM || qname.1 != "set" { + return Err(FromEventsError::Mismatch { name: qname, attrs }); + } + Self::Builder::new(qname, attrs) + } +} + impl From for Element { fn from(set: SetResult) -> Element { let first = set.first.clone().map(|first| { @@ -193,6 +207,14 @@ impl From for Element { } } +impl AsXml for SetResult { + type ItemIter<'x> = minidom_compat::AsItemsViaElement<'x>; + + fn as_xml_iter(&self) -> Result, Error> { + minidom_compat::AsItemsViaElement::new(self.clone()) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/parsers/src/util/macros.rs b/parsers/src/util/macros.rs index 1d9b27b97fd8e98e7363930e1237c464d0962802..7d70c4634717f565d913bad05564945c7d373ca5 100644 --- a/parsers/src/util/macros.rs +++ b/parsers/src/util/macros.rs @@ -762,6 +762,20 @@ macro_rules! impl_pubsub_item { } } + impl ::xso::FromXml for $item { + type Builder = ::xso::minidom_compat::FromEventsViaElement<$item>; + + fn from_events( + qname: ::xso::exports::rxml::QName, + attrs: ::xso::exports::rxml::AttrMap, + ) -> Result { + if qname.0 != crate::ns::$ns || qname.1 != "item" { + return Err(::xso::error::FromEventsError::Mismatch { name: qname, attrs }); + } + Self::Builder::new(qname, attrs) + } + } + impl From<$item> for minidom::Element { fn from(item: $item) -> minidom::Element { minidom::Element::builder("item", ns::$ns) @@ -772,6 +786,14 @@ macro_rules! impl_pubsub_item { } } + impl ::xso::AsXml for $item { + type ItemIter<'x> = ::xso::minidom_compat::AsItemsViaElement<'x>; + + fn as_xml_iter(&self) -> Result, ::xso::error::Error> { + ::xso::minidom_compat::AsItemsViaElement::new(self.clone()) + } + } + impl ::std::ops::Deref for $item { type Target = crate::pubsub::Item;