parsers: port more things to derive macros

This commit is contained in:
Jonas Schäfer 2024-08-03 13:04:56 +02:00
commit 2b346c4e87
18 changed files with 382 additions and 304 deletions

View file

@ -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> = ("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<Info>,
}
impl PubSubPayload for Metadata {}

View file

@ -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> = ("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<Resource>,
}
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> = ("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<Item>,
}
impl IqResultPayload for ListCertsResponse {}

View file

@ -220,25 +220,26 @@ pub struct Item {
pub name: Option<String>,
}
generate_element!(
/// Structure representing a `<query
/// xmlns='http://jabber.org/protocol/disco#items'/>` element.
///
/// It should only be used in an `<iq type='result'/>`, 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<String> = "node"
],
children: [
/// List of items pointed by this entity.
items: Vec<Item> = ("item", DISCO_ITEMS) => Item,
/// Structure representing a `<query
/// xmlns='http://jabber.org/protocol/disco#items'/>` element.
///
/// It should only be used in an `<iq type='result'/>`, 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<String>,
/// Optional paging via Result Set Management
rsm: Option<crate::rsm::SetResult> = ("set", RSM) => SetResult,
]
);
/// List of items pointed by this entity.
#[xml(child(n = ..))]
pub items: Vec<Item>,
/// Optional paging via Result Set Management
#[xml(child(default))]
pub rsm: Option<SetResult>,
}
impl IqResultPayload for DiscoItemsResult {}

View file

@ -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> = ("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<Hash>,
}
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]

View file

@ -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<Type>,
}
impl IqGetPayload for ServicesQuery {}
generate_element!(
/// Structure representing a `<services xmlns='urn:xmpp:extdisco:2'/>` element.
ServicesResult, "services", EXT_DISCO,
attributes: [
/// TODO
type_: Option<Type> = "type",
],
children: [
/// List of services.
services: Vec<Service> = ("service", EXT_DISCO) => Service
]
);
/// Structure representing a `<services xmlns='urn:xmpp:extdisco:2'/>` 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<Type>,
/// List of services.
#[xml(child(n = ..))]
pub services: Vec<Service>,
}
impl IqResultPayload for ServicesResult {}
impl IqSetPayload for ServicesResult {}
generate_element!(
/// Structure representing a `<credentials xmlns='urn:xmpp:extdisco:2'/>` element.
Credentials, "credentials", EXT_DISCO,
children: [
/// List of services.
services: Vec<Service> = ("service", EXT_DISCO) => Service
]
);
/// Structure representing a `<credentials xmlns='urn:xmpp:extdisco:2'/>` 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<Service>,
}
impl IqGetPayload for Credentials {}
impl IqResultPayload for Credentials {}

View file

@ -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<Element> for Header {
}
}
impl FromXml for Header {
type Builder = minidom_compat::FromEventsViaElement<Header>;
fn from_events(
qname: rxml::QName,
attrs: rxml::AttrMap,
) -> Result<Self::Builder, FromEventsError> {
if qname.0 != ns::HTTP_UPLOAD || qname.1 != "header" {
return Err(FromEventsError::Mismatch { name: qname, attrs });
}
Self::Builder::new(qname, attrs)
}
}
impl From<Header> for Element {
fn from(elem: Header) -> Element {
let (attr, val) = match elem {
@ -83,18 +98,26 @@ impl From<Header> for Element {
}
}
generate_element!(
/// Put URL
Put, "put", HTTP_UPLOAD,
attributes: [
/// URL
url: Required<String> = "url",
],
children: [
/// Header list
headers: Vec<Header> = ("header", HTTP_UPLOAD) => Header
]
);
impl AsXml for Header {
type ItemIter<'x> = minidom_compat::AsItemsViaElement<'x>;
fn as_xml_iter(&self) -> Result<Self::ItemIter<'_>, 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<Header>,
}
/// Get URL
#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]

View file

@ -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> = "semantics",
],
children: [
/// List of contents that should be grouped with each other.
contents: Vec<Content> = ("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<Content>,
}
#[cfg(test)]
mod tests {

View file

@ -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<u32> = "ssrc",
],
children: [
/// List of attributes for this source.
parameters: Vec<Parameter> = ("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<Parameter>,
}
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> = "semantics",
],
children: [
/// The various ssrc concerned by this group.
sources: Vec<Source> = ("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<Source>,
}
#[cfg(test)]
mod tests {

View file

@ -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> = ("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<Device>,
}
impl PubSubPayload for DeviceList {}
@ -64,15 +64,15 @@ pub struct IdentityKey {
pub data: Vec<u8>,
}
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> = ("preKeyPublic", LEGACY_OMEMO) => PreKeyPublic,
]
);
#[xml(child(n = ..))]
pub keys: Vec<PreKeyPublic>,
}
/// 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<u32> = "sid",
],
children: [
/// The key that the payload message is encrypted with, separately
/// encrypted for each recipient device.
keys: Vec<Key> = ("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> = ("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<Key>,
/// IV used for payload encryption
#[xml(child)]
pub iv: IV,
}
/// IV used for payload encryption
#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]

View file

@ -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<usize> = "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<usize>,
/// The recommended display height in pixels.
height: Option<usize> = "height"
],
children: [
/// A list of URIs referencing this media.
uris: Vec<Uri> = ("uri", MEDIA_ELEMENT) => Uri
]
);
/// The recommended display height in pixels.
#[xml(attribute(default))]
pub height: Option<usize>,
/// A list of URIs referencing this media.
#[xml(child(n = ..))]
pub uris: Vec<Uri>,
}
#[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]

View file

@ -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<BareJid> = "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> = ("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<BareJid>,
/// 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<Subscribe>,
}
impl IqSetPayload for UpdateSubscription {}
impl IqResultPayload for UpdateSubscription {}

View file

@ -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<PubKeyMeta> = ("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<PubKeyMeta>,
}
impl PubSubPayload for PubKeysMeta {}

View file

@ -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<NodeName> = "node",
],
children: [
/// The actual list of affiliation elements.
affiliations: Vec<Affiliation> = ("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<Affiliation>,
}
/// 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<NodeName> = "node",
],
children: [
/// The list of subscription elements returned.
subscriptions: Vec<SubscriptionElem> = ("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<SubscriptionElem>,
}
/// A subscription element, describing the state of a subscription.
#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]

View file

@ -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<NodeName> = "node",
],
children: [
/// The actual list of affiliation elements.
affiliations: Vec<Affiliation> = ("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<NodeName>,
/// The actual list of affiliation elements.
#[xml(child(n = ..))]
pub affiliations: Vec<Affiliation>,
}
/// An affiliation element.
#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
@ -77,25 +77,27 @@ pub struct Default {
// type_: Option<String>,
}
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<u32> = "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<u32>,
/// The node queried by this request.
node: Required<NodeName> = "node",
/// The node queried by this request.
#[xml(attribute)]
pub node: NodeName,
/// The subscription identifier related to this request.
subid: Option<SubscriptionId> = "subid",
],
children: [
/// The actual list of items returned.
items: Vec<Item> = ("item", PUBSUB) => Item
]
);
/// The subscription identifier related to this request.
#[xml(attribute(default))]
pub subid: Option<SubscriptionId>,
/// The actual list of items returned.
#[xml(child(n = ..))]
pub items: Vec<Item>,
}
impl Items {
/// Create a new items request.
@ -136,18 +138,18 @@ pub struct Options {
pub form: Option<DataForm>,
}
generate_element!(
/// Request to publish items to a node.
Publish, "publish", PUBSUB,
attributes: [
/// The target node for this operation.
node: Required<NodeName> = "node",
],
children: [
/// The items you want to publish.
items: Vec<Item> = ("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<Item>,
}
/// The options associated to a publish request.
#[derive(FromXml, AsXml, Debug, PartialEq, Clone)]
@ -259,18 +261,18 @@ pub struct Subscribe {
pub node: Option<NodeName>,
}
generate_element!(
/// A request for current subscriptions.
Subscriptions, "subscriptions", PUBSUB,
attributes: [
/// The node to query.
node: Option<NodeName> = "node",
],
children: [
/// The list of subscription elements returned.
subscription: Vec<SubscriptionElem> = ("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<NodeName>,
/// The list of subscription elements returned.
#[xml(child(n = ..))]
pub subscription: Vec<SubscriptionElem>,
}
/// A subscription element, describing the state of a subscription.
#[derive(FromXml, AsXml, Debug, PartialEq, Clone)]

View file

@ -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<String> = "id",
],
children: [
/// The list of reactions.
reactions: Vec<Reaction> = ("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<Reaction>,
}
impl MessagePayload for Reactions {}

View file

@ -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<String> = "ver"
],
children: [
/// List of the contacts of the user.
items: Vec<Item> = ("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<String>,
/// List of the contacts of the user.
#[xml(child(n = ..))]
pub items: Vec<Item>,
}
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 = "<query xmlns='jabber:iq:roster' coucou=''/>"
.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]

View file

@ -172,6 +172,20 @@ impl TryFrom<Element> for SetResult {
}
}
impl FromXml for SetResult {
type Builder = minidom_compat::FromEventsViaElement<SetResult>;
fn from_events(
qname: rxml::QName,
attrs: rxml::AttrMap,
) -> Result<Self::Builder, FromEventsError> {
if qname.0 != crate::ns::RSM || qname.1 != "set" {
return Err(FromEventsError::Mismatch { name: qname, attrs });
}
Self::Builder::new(qname, attrs)
}
}
impl From<SetResult> for Element {
fn from(set: SetResult) -> Element {
let first = set.first.clone().map(|first| {
@ -193,6 +207,14 @@ impl From<SetResult> for Element {
}
}
impl AsXml for SetResult {
type ItemIter<'x> = minidom_compat::AsItemsViaElement<'x>;
fn as_xml_iter(&self) -> Result<Self::ItemIter<'_>, Error> {
minidom_compat::AsItemsViaElement::new(self.clone())
}
}
#[cfg(test)]
mod tests {
use super::*;

View file

@ -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<Self::Builder, ::xso::error::FromEventsError> {
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<Self::ItemIter<'_>, ::xso::error::Error> {
::xso::minidom_compat::AsItemsViaElement::new(self.clone())
}
}
impl ::std::ops::Deref for $item {
type Target = crate::pubsub::Item;