xmpp-parsers: Convert the Actor enum into a struct
XEP-0045 doesn’t specify what to do in the case the actor contains both a @jid and a @nick, so let’s not encode anything special about that here. In addition this converted it to use xso. Supersedes !196. Fixes #88.
This commit is contained in:
parent
ce57ee4b38
commit
cd43aa2fcb
1 changed files with 21 additions and 92 deletions
|
|
@ -5,16 +5,11 @@
|
||||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
// 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/.
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
use xso::{
|
use xso::{AsXml, FromXml};
|
||||||
error::{Error, FromElementError, FromEventsError},
|
|
||||||
exports::rxml,
|
|
||||||
minidom_compat, AsXml, FromXml,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::message::MessagePayload;
|
use crate::message::MessagePayload;
|
||||||
use crate::ns;
|
use crate::ns;
|
||||||
use crate::presence::PresencePayload;
|
use crate::presence::PresencePayload;
|
||||||
use minidom::Element;
|
|
||||||
|
|
||||||
use jid::FullJid;
|
use jid::FullJid;
|
||||||
|
|
||||||
|
|
@ -89,67 +84,16 @@ Status, "status", MUC_USER, "code", {
|
||||||
///
|
///
|
||||||
/// Possesses a 'jid' and a 'nick' attribute, so that an action can be attributed either to a real
|
/// Possesses a 'jid' and a 'nick' attribute, so that an action can be attributed either to a real
|
||||||
/// JID or to a roomnick. -- CHANGELOG 1.25 (2012-02-08)
|
/// JID or to a roomnick. -- CHANGELOG 1.25 (2012-02-08)
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(FromXml, AsXml, Debug, Clone, PartialEq)]
|
||||||
pub enum Actor {
|
#[xml(namespace = ns::MUC_USER, name = "actor")]
|
||||||
|
pub struct Actor {
|
||||||
/// The full JID associated with this user.
|
/// The full JID associated with this user.
|
||||||
Jid(FullJid),
|
#[xml(attribute(default))]
|
||||||
|
jid: Option<FullJid>,
|
||||||
|
|
||||||
/// The nickname of this user.
|
/// The nickname of this user.
|
||||||
Nick(String),
|
#[xml(attribute(default))]
|
||||||
}
|
nick: Option<String>,
|
||||||
|
|
||||||
impl TryFrom<Element> for Actor {
|
|
||||||
type Error = FromElementError;
|
|
||||||
|
|
||||||
fn try_from(elem: Element) -> Result<Actor, FromElementError> {
|
|
||||||
check_self!(elem, "actor", MUC_USER);
|
|
||||||
check_no_unknown_attributes!(elem, "actor", ["jid", "nick"]);
|
|
||||||
check_no_children!(elem, "actor");
|
|
||||||
let jid: Option<FullJid> = get_attr!(elem, "jid", Option);
|
|
||||||
let nick = get_attr!(elem, "nick", Option);
|
|
||||||
|
|
||||||
match (jid, nick) {
|
|
||||||
(Some(_), Some(_)) | (None, None) => {
|
|
||||||
Err(Error::Other("Either 'jid' or 'nick' attribute is required.").into())
|
|
||||||
}
|
|
||||||
(Some(jid), _) => Ok(Actor::Jid(jid)),
|
|
||||||
(_, Some(nick)) => Ok(Actor::Nick(nick)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromXml for Actor {
|
|
||||||
type Builder = minidom_compat::FromEventsViaElement<Actor>;
|
|
||||||
|
|
||||||
fn from_events(
|
|
||||||
qname: rxml::QName,
|
|
||||||
attrs: rxml::AttrMap,
|
|
||||||
) -> Result<Self::Builder, FromEventsError> {
|
|
||||||
if qname.0 != crate::ns::MUC_USER || qname.1 != "actor" {
|
|
||||||
return Err(FromEventsError::Mismatch { name: qname, attrs });
|
|
||||||
}
|
|
||||||
Self::Builder::new(qname, attrs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Actor> for Element {
|
|
||||||
fn from(actor: Actor) -> Element {
|
|
||||||
let elem = Element::builder("actor", ns::MUC_USER);
|
|
||||||
|
|
||||||
(match actor {
|
|
||||||
Actor::Jid(jid) => elem.attr("jid", jid),
|
|
||||||
Actor::Nick(nick) => elem.attr("nick", nick),
|
|
||||||
})
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsXml for Actor {
|
|
||||||
type ItemIter<'x> = minidom_compat::AsItemsViaElement<'x>;
|
|
||||||
|
|
||||||
fn as_xml_iter(&self) -> Result<Self::ItemIter<'_>, Error> {
|
|
||||||
minidom_compat::AsItemsViaElement::new(self.clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used to continue a one-to-one discussion in a room, with more than one
|
/// Used to continue a one-to-one discussion in a room, with more than one
|
||||||
|
|
@ -343,6 +287,8 @@ mod tests {
|
||||||
use crate::message::Message;
|
use crate::message::Message;
|
||||||
use crate::presence::{Presence, Type as PresenceType};
|
use crate::presence::{Presence, Type as PresenceType};
|
||||||
use jid::Jid;
|
use jid::Jid;
|
||||||
|
use minidom::Element;
|
||||||
|
use xso::error::{Error, FromElementError};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_simple() {
|
fn test_simple() {
|
||||||
|
|
@ -488,7 +434,10 @@ mod tests {
|
||||||
assert_eq!(error.to_string(), "invalid digit found in string");
|
assert_eq!(error.to_string(), "invalid digit found in string");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This test is now ignored because we switched to a representation where we can’t currently
|
||||||
|
// validate whether one of the required attributes is present or not.
|
||||||
#[test]
|
#[test]
|
||||||
|
#[ignore]
|
||||||
fn test_actor_required_attributes() {
|
fn test_actor_required_attributes() {
|
||||||
let elem: Element = "<actor xmlns='http://jabber.org/protocol/muc#user'/>"
|
let elem: Element = "<actor xmlns='http://jabber.org/protocol/muc#user'/>"
|
||||||
.parse()
|
.parse()
|
||||||
|
|
@ -501,21 +450,6 @@ mod tests {
|
||||||
assert_eq!(message, "Either 'jid' or 'nick' attribute is required.");
|
assert_eq!(message, "Either 'jid' or 'nick' attribute is required.");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_actor_required_attributes2() {
|
|
||||||
let elem: Element = "<actor xmlns='http://jabber.org/protocol/muc#user'
|
|
||||||
jid='foo@bar/baz'
|
|
||||||
nick='baz'/>"
|
|
||||||
.parse()
|
|
||||||
.unwrap();
|
|
||||||
let error = Actor::try_from(elem).unwrap_err();
|
|
||||||
let message = match error {
|
|
||||||
FromElementError::Invalid(Error::Other(string)) => string,
|
|
||||||
_ => panic!(),
|
|
||||||
};
|
|
||||||
assert_eq!(message, "Either 'jid' or 'nick' attribute is required.");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_actor_jid() {
|
fn test_actor_jid() {
|
||||||
let elem: Element = "<actor xmlns='http://jabber.org/protocol/muc#user'
|
let elem: Element = "<actor xmlns='http://jabber.org/protocol/muc#user'
|
||||||
|
|
@ -523,11 +457,8 @@ mod tests {
|
||||||
.parse()
|
.parse()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let actor = Actor::try_from(elem).unwrap();
|
let actor = Actor::try_from(elem).unwrap();
|
||||||
let jid = match actor {
|
assert_eq!(actor.jid, Some("foo@bar/baz".parse::<FullJid>().unwrap()));
|
||||||
Actor::Jid(jid) => jid,
|
assert_eq!(actor.nick, None);
|
||||||
_ => panic!(),
|
|
||||||
};
|
|
||||||
assert_eq!(jid, "foo@bar/baz".parse::<FullJid>().unwrap());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -536,11 +467,8 @@ mod tests {
|
||||||
.parse()
|
.parse()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let actor = Actor::try_from(elem).unwrap();
|
let actor = Actor::try_from(elem).unwrap();
|
||||||
let nick = match actor {
|
assert_eq!(actor.nick, Some("baz".to_owned()));
|
||||||
Actor::Nick(nick) => nick,
|
assert_eq!(actor.jid, None);
|
||||||
_ => panic!(),
|
|
||||||
};
|
|
||||||
assert_eq!(nick, "baz".to_owned());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -703,9 +631,10 @@ mod tests {
|
||||||
.parse()
|
.parse()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let item = Item::try_from(elem).unwrap();
|
let item = Item::try_from(elem).unwrap();
|
||||||
match item {
|
let Item { actor, .. } = item;
|
||||||
Item { actor, .. } => assert_eq!(actor, Some(Actor::Nick("foobar".to_owned()))),
|
let actor = actor.unwrap();
|
||||||
}
|
assert_eq!(actor.nick, Some("foobar".to_owned()));
|
||||||
|
assert_eq!(actor.jid, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue