parsers: port enums over to derive macros

This commit is contained in:
Jonas Schäfer 2024-07-10 16:38:00 +02:00
commit 6afd0ef52f
7 changed files with 563 additions and 428 deletions

View file

@ -1,5 +1,10 @@
Version NEXT: Version NEXT:
XXXX-YY-ZZ RELEASER <admin@example.com> XXXX-YY-ZZ RELEASER <admin@example.com>
* Breaking
- The `alternate_address` field of
`xmpp_parsers::stanza_error::StanzaError` has been moved into the
corresponding enum variants of the
`xmpp_parsers::stanza_error::DefinedCondition` where it may occur.
* New parsers/serialisers: * New parsers/serialisers:
- Stream Features (RFC 6120) (!400) - Stream Features (RFC 6120) (!400)

View file

@ -4,28 +4,36 @@
// 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 crate::message::MessagePayload; use xso::{AsXml, FromXml};
use crate::message::MessagePayload;
use crate::ns;
generate_element_enum!(
/// Enum representing chatstate elements part of the /// Enum representing chatstate elements part of the
/// `http://jabber.org/protocol/chatstates` namespace. /// `http://jabber.org/protocol/chatstates` namespace.
ChatState, "chatstate", CHATSTATES, { #[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
#[xml(namespace = ns::CHATSTATES, exhaustive)]
pub enum ChatState {
/// `<active xmlns='http://jabber.org/protocol/chatstates'/>` /// `<active xmlns='http://jabber.org/protocol/chatstates'/>`
Active => "active", #[xml(name = "active")]
Active,
/// `<composing xmlns='http://jabber.org/protocol/chatstates'/>` /// `<composing xmlns='http://jabber.org/protocol/chatstates'/>`
Composing => "composing", #[xml(name = "composing")]
Composing,
/// `<gone xmlns='http://jabber.org/protocol/chatstates'/>` /// `<gone xmlns='http://jabber.org/protocol/chatstates'/>`
Gone => "gone", #[xml(name = "gone")]
Gone,
/// `<inactive xmlns='http://jabber.org/protocol/chatstates'/>` /// `<inactive xmlns='http://jabber.org/protocol/chatstates'/>`
Inactive => "inactive", #[xml(name = "inactive")]
Inactive,
/// `<paused xmlns='http://jabber.org/protocol/chatstates'/>` /// `<paused xmlns='http://jabber.org/protocol/chatstates'/>`
Paused => "paused", #[xml(name = "paused")]
Paused,
} }
);
impl MessagePayload for ChatState {} impl MessagePayload for ChatState {}
@ -59,7 +67,7 @@ mod tests {
FromElementError::Invalid(Error::Other(string)) => string, FromElementError::Invalid(Error::Other(string)) => string,
_ => panic!(), _ => panic!(),
}; };
assert_eq!(message, "This is not a chatstate element."); assert_eq!(message, "This is not a ChatState element.");
} }
#[cfg(not(feature = "disable-validation"))] #[cfg(not(feature = "disable-validation"))]
@ -73,7 +81,7 @@ mod tests {
FromElementError::Invalid(Error::Other(string)) => string, FromElementError::Invalid(Error::Other(string)) => string,
_ => panic!(), _ => panic!(),
}; };
assert_eq!(message, "Unknown child in chatstate element."); assert_eq!(message, "Unknown child in ChatState::Gone element.");
} }
#[cfg(not(feature = "disable-validation"))] #[cfg(not(feature = "disable-validation"))]
@ -87,7 +95,7 @@ mod tests {
FromElementError::Invalid(Error::Other(string)) => string, FromElementError::Invalid(Error::Other(string)) => string,
_ => panic!(), _ => panic!(),
}; };
assert_eq!(message, "Unknown attribute in chatstate element."); assert_eq!(message, "Unknown attribute in ChatState::Inactive element.");
} }
#[test] #[test]

View file

@ -232,15 +232,15 @@ mod tests {
#[cfg(target_pointer_width = "32")] #[cfg(target_pointer_width = "32")]
#[test] #[test]
fn test_size() { fn test_size() {
assert_size!(IqType, 104); assert_size!(IqType, 108);
assert_size!(Iq, 148); assert_size!(Iq, 152);
} }
#[cfg(target_pointer_width = "64")] #[cfg(target_pointer_width = "64")]
#[test] #[test]
fn test_size() { fn test_size() {
assert_size!(IqType, 208); assert_size!(IqType, 216);
assert_size!(Iq, 296); assert_size!(Iq, 304);
} }
#[test] #[test]

View file

@ -4,262 +4,350 @@
// 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/.
generate_element_enum!( use xso::{AsXml, FromXml};
use crate::ns;
/// Enum representing all of the possible values of the XEP-0107 moods. /// Enum representing all of the possible values of the XEP-0107 moods.
MoodEnum, "mood", MOOD, { #[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
#[xml(namespace = ns::MOOD, exhaustive)]
pub enum MoodEnum {
/// Impressed with fear or apprehension; in fear; apprehensive. /// Impressed with fear or apprehension; in fear; apprehensive.
Afraid => "afraid", #[xml(name = "afraid")]
Afraid,
/// Astonished; confounded with fear, surprise or wonder. /// Astonished; confounded with fear, surprise or wonder.
Amazed => "amazed", #[xml(name = "amazed")]
Amazed,
/// Inclined to love; having a propensity to love, or to sexual enjoyment; loving, fond, affectionate, passionate, lustful, sexual, etc. /// Inclined to love; having a propensity to love, or to sexual enjoyment; loving, fond, affectionate, passionate, lustful, sexual, etc.
Amorous => "amorous", #[xml(name = "amorous")]
Amorous,
/// Displaying or feeling anger, i.e., a strong feeling of displeasure, hostility or antagonism towards someone or something, usually combined with an urge to harm. /// Displaying or feeling anger, i.e., a strong feeling of displeasure, hostility or antagonism towards someone or something, usually combined with an urge to harm.
Angry => "angry", #[xml(name = "angry")]
Angry,
/// To be disturbed or irritated, especially by continued or repeated acts. /// To be disturbed or irritated, especially by continued or repeated acts.
Annoyed => "annoyed", #[xml(name = "annoyed")]
Annoyed,
/// Full of anxiety or disquietude; greatly concerned or solicitous, esp. respecting something future or unknown; being in painful suspense. /// Full of anxiety or disquietude; greatly concerned or solicitous, esp. respecting something future or unknown; being in painful suspense.
Anxious => "anxious", #[xml(name = "anxious")]
Anxious,
/// To be stimulated in one's feelings, especially to be sexually stimulated. /// To be stimulated in one's feelings, especially to be sexually stimulated.
Aroused => "aroused", #[xml(name = "aroused")]
Aroused,
/// Feeling shame or guilt. /// Feeling shame or guilt.
Ashamed => "ashamed", #[xml(name = "ashamed")]
Ashamed,
/// Suffering from boredom; uninterested, without attention. /// Suffering from boredom; uninterested, without attention.
Bored => "bored", #[xml(name = "bored")]
Bored,
/// Strong in the face of fear; courageous. /// Strong in the face of fear; courageous.
Brave => "brave", #[xml(name = "brave")]
Brave,
/// Peaceful, quiet. /// Peaceful, quiet.
Calm => "calm", #[xml(name = "calm")]
Calm,
/// Taking care or caution; tentative. /// Taking care or caution; tentative.
Cautious => "cautious", #[xml(name = "cautious")]
Cautious,
/// Feeling the sensation of coldness, especially to the point of discomfort. /// Feeling the sensation of coldness, especially to the point of discomfort.
Cold => "cold", #[xml(name = "cold")]
Cold,
/// Feeling very sure of or positive about something, especially about one's own capabilities. /// Feeling very sure of or positive about something, especially about one's own capabilities.
Confident => "confident", #[xml(name = "confident")]
Confident,
/// Chaotic, jumbled or muddled. /// Chaotic, jumbled or muddled.
Confused => "confused", #[xml(name = "confused")]
Confused,
/// Feeling introspective or thoughtful. /// Feeling introspective or thoughtful.
Contemplative => "contemplative", #[xml(name = "contemplative")]
Contemplative,
/// Pleased at the satisfaction of a want or desire; satisfied. /// Pleased at the satisfaction of a want or desire; satisfied.
Contented => "contented", #[xml(name = "contented")]
Contented,
/// Grouchy, irritable; easily upset. /// Grouchy, irritable; easily upset.
Cranky => "cranky", #[xml(name = "cranky")]
Cranky,
/// Feeling out of control; feeling overly excited or enthusiastic. /// Feeling out of control; feeling overly excited or enthusiastic.
Crazy => "crazy", #[xml(name = "crazy")]
Crazy,
/// Feeling original, expressive, or imaginative. /// Feeling original, expressive, or imaginative.
Creative => "creative", #[xml(name = "creative")]
Creative,
/// Inquisitive; tending to ask questions, investigate, or explore. /// Inquisitive; tending to ask questions, investigate, or explore.
Curious => "curious", #[xml(name = "curious")]
Curious,
/// Feeling sad and dispirited. /// Feeling sad and dispirited.
Dejected => "dejected", #[xml(name = "dejected")]
Dejected,
/// Severely despondent and unhappy. /// Severely despondent and unhappy.
Depressed => "depressed", #[xml(name = "depressed")]
Depressed,
/// Defeated of expectation or hope; let down. /// Defeated of expectation or hope; let down.
Disappointed => "disappointed", #[xml(name = "disappointed")]
Disappointed,
/// Filled with disgust; irritated and out of patience. /// Filled with disgust; irritated and out of patience.
Disgusted => "disgusted", #[xml(name = "disgusted")]
Disgusted,
/// Feeling a sudden or complete loss of courage in the face of trouble or danger. /// Feeling a sudden or complete loss of courage in the face of trouble or danger.
Dismayed => "dismayed", #[xml(name = "dismayed")]
Dismayed,
/// Having one's attention diverted; preoccupied. /// Having one's attention diverted; preoccupied.
Distracted => "distracted", #[xml(name = "distracted")]
Distracted,
/// Having a feeling of shameful discomfort. /// Having a feeling of shameful discomfort.
Embarrassed => "embarrassed", #[xml(name = "embarrassed")]
Embarrassed,
/// Feeling pain by the excellence or good fortune of another. /// Feeling pain by the excellence or good fortune of another.
Envious => "envious", #[xml(name = "envious")]
Envious,
/// Having great enthusiasm. /// Having great enthusiasm.
Excited => "excited", #[xml(name = "excited")]
Excited,
/// In the mood for flirting. /// In the mood for flirting.
Flirtatious => "flirtatious", #[xml(name = "flirtatious")]
Flirtatious,
/// Suffering from frustration; dissatisfied, agitated, or discontented because one is unable to perform an action or fulfill a desire. /// Suffering from frustration; dissatisfied, agitated, or discontented because one is unable to perform an action or fulfill a desire.
Frustrated => "frustrated", #[xml(name = "frustrated")]
Frustrated,
/// Feeling appreciation or thanks. /// Feeling appreciation or thanks.
Grateful => "grateful", #[xml(name = "grateful")]
Grateful,
/// Feeling very sad about something, especially something lost; mournful; sorrowful. /// Feeling very sad about something, especially something lost; mournful; sorrowful.
Grieving => "grieving", #[xml(name = "grieving")]
Grieving,
/// Unhappy and irritable. /// Unhappy and irritable.
Grumpy => "grumpy", #[xml(name = "grumpy")]
Grumpy,
/// Feeling responsible for wrongdoing; feeling blameworthy. /// Feeling responsible for wrongdoing; feeling blameworthy.
Guilty => "guilty", #[xml(name = "guilty")]
Guilty,
/// Experiencing the effect of favourable fortune; having the feeling arising from the consciousness of well-being or of enjoyment; enjoying good of any kind, as peace, tranquillity, comfort; contented; joyous. /// Experiencing the effect of favourable fortune; having the feeling arising from the consciousness of well-being or of enjoyment; enjoying good of any kind, as peace, tranquillity, comfort; contented; joyous.
Happy => "happy", #[xml(name = "happy")]
Happy,
/// Having a positive feeling, belief, or expectation that something wished for can or will happen. /// Having a positive feeling, belief, or expectation that something wished for can or will happen.
Hopeful => "hopeful", #[xml(name = "hopeful")]
Hopeful,
/// Feeling the sensation of heat, especially to the point of discomfort. /// Feeling the sensation of heat, especially to the point of discomfort.
Hot => "hot", #[xml(name = "hot")]
Hot,
/// Having or showing a modest or low estimate of one's own importance; feeling lowered in dignity or importance. /// Having or showing a modest or low estimate of one's own importance; feeling lowered in dignity or importance.
Humbled => "humbled", #[xml(name = "humbled")]
Humbled,
/// Feeling deprived of dignity or self-respect. /// Feeling deprived of dignity or self-respect.
Humiliated => "humiliated", #[xml(name = "humiliated")]
Humiliated,
/// Having a physical need for food. /// Having a physical need for food.
Hungry => "hungry", #[xml(name = "hungry")]
Hungry,
/// Wounded, injured, or pained, whether physically or emotionally. /// Wounded, injured, or pained, whether physically or emotionally.
Hurt => "hurt", #[xml(name = "hurt")]
Hurt,
/// Favourably affected by something or someone. /// Favourably affected by something or someone.
Impressed => "impressed", #[xml(name = "impressed")]
Impressed,
/// Feeling amazement at something or someone; or feeling a combination of fear and reverence. /// Feeling amazement at something or someone; or feeling a combination of fear and reverence.
InAwe => "in_awe", #[xml(name = "in_awe")]
InAwe,
/// Feeling strong affection, care, liking, or attraction.. /// Feeling strong affection, care, liking, or attraction..
InLove => "in_love", #[xml(name = "in_love")]
InLove,
/// Showing anger or indignation, especially at something unjust or wrong. /// Showing anger or indignation, especially at something unjust or wrong.
Indignant => "indignant", #[xml(name = "indignant")]
Indignant,
/// Showing great attention to something or someone; having or showing interest. /// Showing great attention to something or someone; having or showing interest.
Interested => "interested", #[xml(name = "interested")]
Interested,
/// Under the influence of alcohol; drunk. /// Under the influence of alcohol; drunk.
Intoxicated => "intoxicated", #[xml(name = "intoxicated")]
Intoxicated,
/// Feeling as if one cannot be defeated, overcome or denied. /// Feeling as if one cannot be defeated, overcome or denied.
Invincible => "invincible", #[xml(name = "invincible")]
Invincible,
/// Fearful of being replaced in position or affection. /// Fearful of being replaced in position or affection.
Jealous => "jealous", #[xml(name = "jealous")]
Jealous,
/// Feeling isolated, empty, or abandoned. /// Feeling isolated, empty, or abandoned.
Lonely => "lonely", #[xml(name = "lonely")]
Lonely,
/// Unable to find one's way, either physically or emotionally. /// Unable to find one's way, either physically or emotionally.
Lost => "lost", #[xml(name = "lost")]
Lost,
/// Feeling as if one will be favored by luck. /// Feeling as if one will be favored by luck.
Lucky => "lucky", #[xml(name = "lucky")]
Lucky,
/// Causing or intending to cause intentional harm; bearing ill will towards another; cruel; malicious. /// Causing or intending to cause intentional harm; bearing ill will towards another; cruel; malicious.
Mean => "mean", #[xml(name = "mean")]
Mean,
/// Given to sudden or frequent changes of mind or feeling; temperamental. /// Given to sudden or frequent changes of mind or feeling; temperamental.
Moody => "moody", #[xml(name = "moody")]
Moody,
/// Easily agitated or alarmed; apprehensive or anxious. /// Easily agitated or alarmed; apprehensive or anxious.
Nervous => "nervous", #[xml(name = "nervous")]
Nervous,
/// Not having a strong mood or emotional state. /// Not having a strong mood or emotional state.
Neutral => "neutral", #[xml(name = "neutral")]
Neutral,
/// Feeling emotionally hurt, displeased, or insulted. /// Feeling emotionally hurt, displeased, or insulted.
Offended => "offended", #[xml(name = "offended")]
Offended,
/// Feeling resentful anger caused by an extremely violent or vicious attack, or by an offensive, immoral, or indecent act. /// Feeling resentful anger caused by an extremely violent or vicious attack, or by an offensive, immoral, or indecent act.
Outraged => "outraged", #[xml(name = "outraged")]
Outraged,
/// Interested in play; fun, recreational, unserious, lighthearted; joking, silly. /// Interested in play; fun, recreational, unserious, lighthearted; joking, silly.
Playful => "playful", #[xml(name = "playful")]
Playful,
/// Feeling a sense of one's own worth or accomplishment. /// Feeling a sense of one's own worth or accomplishment.
Proud => "proud", #[xml(name = "proud")]
Proud,
/// Having an easy-going mood; not stressed; calm. /// Having an easy-going mood; not stressed; calm.
Relaxed => "relaxed", #[xml(name = "relaxed")]
Relaxed,
/// Feeling uplifted because of the removal of stress or discomfort. /// Feeling uplifted because of the removal of stress or discomfort.
Relieved => "relieved", #[xml(name = "relieved")]
Relieved,
/// Feeling regret or sadness for doing something wrong. /// Feeling regret or sadness for doing something wrong.
Remorseful => "remorseful", #[xml(name = "remorseful")]
Remorseful,
/// Without rest; unable to be still or quiet; uneasy; continually moving. /// Without rest; unable to be still or quiet; uneasy; continually moving.
Restless => "restless", #[xml(name = "restless")]
Restless,
/// Feeling sorrow; sorrowful, mournful. /// Feeling sorrow; sorrowful, mournful.
Sad => "sad", #[xml(name = "sad")]
Sad,
/// Mocking and ironical. /// Mocking and ironical.
Sarcastic => "sarcastic", #[xml(name = "sarcastic")]
Sarcastic,
/// Pleased at the fulfillment of a need or desire. /// Pleased at the fulfillment of a need or desire.
Satisfied => "satisfied", #[xml(name = "satisfied")]
Satisfied,
/// Without humor or expression of happiness; grave in manner or disposition; earnest; thoughtful; solemn. /// Without humor or expression of happiness; grave in manner or disposition; earnest; thoughtful; solemn.
Serious => "serious", #[xml(name = "serious")]
Serious,
/// Surprised, startled, confused, or taken aback. /// Surprised, startled, confused, or taken aback.
Shocked => "shocked", #[xml(name = "shocked")]
Shocked,
/// Feeling easily frightened or scared; timid; reserved or coy. /// Feeling easily frightened or scared; timid; reserved or coy.
Shy => "shy", #[xml(name = "shy")]
Shy,
/// Feeling in poor health; ill. /// Feeling in poor health; ill.
Sick => "sick", #[xml(name = "sick")]
Sick,
/// Feeling the need for sleep. /// Feeling the need for sleep.
Sleepy => "sleepy", #[xml(name = "sleepy")]
Sleepy,
/// Acting without planning; natural; impulsive. /// Acting without planning; natural; impulsive.
Spontaneous => "spontaneous", #[xml(name = "spontaneous")]
Spontaneous,
/// Suffering emotional pressure. /// Suffering emotional pressure.
Stressed => "stressed", #[xml(name = "stressed")]
Stressed,
/// Capable of producing great physical force; or, emotionally forceful, able, determined, unyielding. /// Capable of producing great physical force; or, emotionally forceful, able, determined, unyielding.
Strong => "strong", #[xml(name = "strong")]
Strong,
/// Experiencing a feeling caused by something unexpected. /// Experiencing a feeling caused by something unexpected.
Surprised => "surprised", #[xml(name = "surprised")]
Surprised,
/// Showing appreciation or gratitude. /// Showing appreciation or gratitude.
Thankful => "thankful", #[xml(name = "thankful")]
Thankful,
/// Feeling the need to drink. /// Feeling the need to drink.
Thirsty => "thirsty", #[xml(name = "thirsty")]
Thirsty,
/// In need of rest or sleep. /// In need of rest or sleep.
Tired => "tired", #[xml(name = "tired")]
Tired,
/// [Feeling any emotion not defined here.] /// [Feeling any emotion not defined here.]
Undefined => "undefined", #[xml(name = "undefined")]
Undefined,
/// Lacking in force or ability, either physical or emotional. /// Lacking in force or ability, either physical or emotional.
Weak => "weak", #[xml(name = "weak")]
Weak,
/// Thinking about unpleasant things that have happened or that might happen; feeling afraid and unhappy. /// Thinking about unpleasant things that have happened or that might happen; feeling afraid and unhappy.
Worried => "worried", #[xml(name = "worried")]
Worried,
} }
);
generate_elem_id!( generate_elem_id!(
/// Free-form text description of the mood. /// Free-form text description of the mood.

View file

@ -97,47 +97,58 @@ pub struct Success {
pub data: Vec<u8>, pub data: Vec<u8>,
} }
generate_element_enum!(
/// List of possible failure conditions for SASL. /// List of possible failure conditions for SASL.
DefinedCondition, "defined-condition", SASL, { #[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
#[xml(namespace = ns::SASL, exhaustive)]
pub enum DefinedCondition {
/// The client aborted the authentication with /// The client aborted the authentication with
/// [abort](struct.Abort.html). /// [abort](struct.Abort.html).
Aborted => "aborted", #[xml(name = "aborted")]
Aborted,
/// The account the client is trying to authenticate against has been /// The account the client is trying to authenticate against has been
/// disabled. /// disabled.
AccountDisabled => "account-disabled", #[xml(name = "account-disabled")]
AccountDisabled,
/// The credentials for this account have expired. /// The credentials for this account have expired.
CredentialsExpired => "credentials-expired", #[xml(name = "credentials-expired")]
CredentialsExpired,
/// You must enable StartTLS or use direct TLS before using this /// You must enable StartTLS or use direct TLS before using this
/// authentication mechanism. /// authentication mechanism.
EncryptionRequired => "encryption-required", #[xml(name = "encryption-required")]
EncryptionRequired,
/// The base64 data sent by the client is invalid. /// The base64 data sent by the client is invalid.
IncorrectEncoding => "incorrect-encoding", #[xml(name = "incorrect-encoding")]
IncorrectEncoding,
/// The authzid provided by the client is invalid. /// The authzid provided by the client is invalid.
InvalidAuthzid => "invalid-authzid", #[xml(name = "invalid-authzid")]
InvalidAuthzid,
/// The client tried to use an invalid mechanism, or none. /// The client tried to use an invalid mechanism, or none.
InvalidMechanism => "invalid-mechanism", #[xml(name = "invalid-mechanism")]
InvalidMechanism,
/// The client sent a bad request. /// The client sent a bad request.
MalformedRequest => "malformed-request", #[xml(name = "malformed-request")]
MalformedRequest,
/// The mechanism selected is weaker than what the server allows. /// The mechanism selected is weaker than what the server allows.
MechanismTooWeak => "mechanism-too-weak", #[xml(name = "mechanism-too-weak")]
MechanismTooWeak,
/// The credentials provided are invalid. /// The credentials provided are invalid.
NotAuthorized => "not-authorized", #[xml(name = "not-authorized")]
NotAuthorized,
/// The server encountered an issue which may be fixed later, the /// The server encountered an issue which may be fixed later, the
/// client should retry at some point. /// client should retry at some point.
TemporaryAuthFailure => "temporary-auth-failure", #[xml(name = "temporary-auth-failure")]
TemporaryAuthFailure,
} }
);
type Lang = String; type Lang = String;

View file

@ -159,7 +159,7 @@ mod tests {
assert_size!(Enable, 12); assert_size!(Enable, 12);
assert_size!(StreamId, 12); assert_size!(StreamId, 12);
assert_size!(Enabled, 36); assert_size!(Enabled, 36);
assert_size!(Failed, 12); assert_size!(Failed, 24);
assert_size!(R, 0); assert_size!(R, 0);
assert_size!(Resume, 16); assert_size!(Resume, 16);
assert_size!(Resumed, 16); assert_size!(Resumed, 16);
@ -174,7 +174,7 @@ mod tests {
assert_size!(Enable, 12); assert_size!(Enable, 12);
assert_size!(StreamId, 24); assert_size!(StreamId, 24);
assert_size!(Enabled, 64); assert_size!(Enabled, 64);
assert_size!(Failed, 12); assert_size!(Failed, 40);
assert_size!(R, 0); assert_size!(R, 0);
assert_size!(Resume, 32); assert_size!(Resume, 32);
assert_size!(Resumed, 32); assert_size!(Resumed, 32);

View file

@ -4,12 +4,13 @@
// 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::{text::EmptyAsNone, 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 jid::Jid; use jid::Jid;
use minidom::Element; use minidom::Element;
use minidom::Node;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::convert::TryFrom; use std::convert::TryFrom;
use xso::error::{Error, FromElementError}; use xso::error::{Error, FromElementError};
@ -34,35 +35,40 @@ generate_attribute!(
} }
); );
generate_element_enum!(
/// List of valid error conditions. /// List of valid error conditions.
DefinedCondition, "condition", XMPP_STANZAS, { #[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
#[xml(namespace = ns::XMPP_STANZAS, exhaustive)]
pub enum DefinedCondition {
/// The sender has sent a stanza containing XML that does not conform /// The sender has sent a stanza containing XML that does not conform
/// to the appropriate schema or that cannot be processed (e.g., an IQ /// to the appropriate schema or that cannot be processed (e.g., an IQ
/// stanza that includes an unrecognized value of the 'type' attribute, /// stanza that includes an unrecognized value of the 'type' attribute,
/// or an element that is qualified by a recognized namespace but that /// or an element that is qualified by a recognized namespace but that
/// violates the defined syntax for the element); the associated error /// violates the defined syntax for the element); the associated error
/// type SHOULD be "modify". /// type SHOULD be "modify".
BadRequest => "bad-request", #[xml(name = "bad-request")]
BadRequest,
/// Access cannot be granted because an existing resource exists with /// Access cannot be granted because an existing resource exists with
/// the same name or address; the associated error type SHOULD be /// the same name or address; the associated error type SHOULD be
/// "cancel". /// "cancel".
Conflict => "conflict", #[xml(name = "conflict")]
Conflict,
/// The feature represented in the XML stanza is not implemented by the /// The feature represented in the XML stanza is not implemented by the
/// intended recipient or an intermediate server and therefore the /// intended recipient or an intermediate server and therefore the
/// stanza cannot be processed (e.g., the entity understands the /// stanza cannot be processed (e.g., the entity understands the
/// namespace but does not recognize the element name); the associated /// namespace but does not recognize the element name); the associated
/// error type SHOULD be "cancel" or "modify". /// error type SHOULD be "cancel" or "modify".
FeatureNotImplemented => "feature-not-implemented", #[xml(name = "feature-not-implemented")]
FeatureNotImplemented,
/// The requesting entity does not possess the necessary permissions to /// The requesting entity does not possess the necessary permissions to
/// perform an action that only certain authorized roles or individuals /// perform an action that only certain authorized roles or individuals
/// are allowed to complete (i.e., it typically relates to /// are allowed to complete (i.e., it typically relates to
/// authorization rather than authentication); the associated error /// authorization rather than authentication); the associated error
/// type SHOULD be "auth". /// type SHOULD be "auth".
Forbidden => "forbidden", #[xml(name = "forbidden")]
Forbidden,
/// The recipient or server can no longer be contacted at this address, /// The recipient or server can no longer be contacted at this address,
/// typically on a permanent basis (as opposed to the \<redirect/\> error /// typically on a permanent basis (as opposed to the \<redirect/\> error
@ -73,22 +79,31 @@ generate_element_enum!(
/// Identifier (URI) or Internationalized Resource Identifier (IRI) at /// Identifier (URI) or Internationalized Resource Identifier (IRI) at
/// which the entity can be contacted, typically an XMPP IRI as /// which the entity can be contacted, typically an XMPP IRI as
/// specified in [XMPPURI](https://www.rfc-editor.org/rfc/rfc5122)). /// specified in [XMPPURI](https://www.rfc-editor.org/rfc/rfc5122)).
Gone => "gone", #[xml(name = "gone")]
Gone {
/// The new address of the entity for which the error was returned,
/// if available.
#[xml(text(codec = EmptyAsNone))]
new_address: Option<String>,
},
/// The server has experienced a misconfiguration or other internal /// The server has experienced a misconfiguration or other internal
/// error that prevents it from processing the stanza; the associated /// error that prevents it from processing the stanza; the associated
/// error type SHOULD be "cancel". /// error type SHOULD be "cancel".
InternalServerError => "internal-server-error", #[xml(name = "internal-server-error")]
InternalServerError,
/// The addressed JID or item requested cannot be found; the associated /// The addressed JID or item requested cannot be found; the associated
/// error type SHOULD be "cancel". /// error type SHOULD be "cancel".
ItemNotFound => "item-not-found", #[xml(name = "item-not-found")]
ItemNotFound,
/// The sending entity has provided (e.g., during resource binding) or /// The sending entity has provided (e.g., during resource binding) or
/// communicated (e.g., in the 'to' address of a stanza) an XMPP /// communicated (e.g., in the 'to' address of a stanza) an XMPP
/// address or aspect thereof that violates the rules defined in /// address or aspect thereof that violates the rules defined in
/// [XMPPADDR]; the associated error type SHOULD be "modify". /// [XMPPADDR]; the associated error type SHOULD be "modify".
JidMalformed => "jid-malformed", #[xml(name = "jid-malformed")]
JidMalformed,
/// The recipient or server understands the request but cannot process /// The recipient or server understands the request but cannot process
/// it because the request does not meet criteria defined by the /// it because the request does not meet criteria defined by the
@ -96,12 +111,14 @@ generate_element_enum!(
/// that does not simultaneously include configuration parameters /// that does not simultaneously include configuration parameters
/// needed by the recipient); the associated error type SHOULD be /// needed by the recipient); the associated error type SHOULD be
/// "modify". /// "modify".
NotAcceptable => "not-acceptable", #[xml(name = "not-acceptable")]
NotAcceptable,
/// The recipient or server does not allow any entity to perform the /// The recipient or server does not allow any entity to perform the
/// action (e.g., sending to entities at a blacklisted domain); the /// action (e.g., sending to entities at a blacklisted domain); the
/// associated error type SHOULD be "cancel". /// associated error type SHOULD be "cancel".
NotAllowed => "not-allowed", #[xml(name = "not-allowed")]
NotAllowed,
/// The sender needs to provide credentials before being allowed to /// The sender needs to provide credentials before being allowed to
/// perform the action, or has provided improper credentials (the name /// perform the action, or has provided improper credentials (the name
@ -110,7 +127,8 @@ generate_element_enum!(
/// relates to authorization, but instead it is typically used in /// relates to authorization, but instead it is typically used in
/// relation to authentication); the associated error type SHOULD be /// relation to authentication); the associated error type SHOULD be
/// "auth". /// "auth".
NotAuthorized => "not-authorized", #[xml(name = "not-authorized")]
NotAuthorized,
/// The entity has violated some local service policy (e.g., a message /// The entity has violated some local service policy (e.g., a message
/// contains words that are prohibited by the service) and the server /// contains words that are prohibited by the service) and the server
@ -118,11 +136,13 @@ generate_element_enum!(
/// application-specific condition element; the associated error type /// application-specific condition element; the associated error type
/// SHOULD be "modify" or "wait" depending on the policy being /// SHOULD be "modify" or "wait" depending on the policy being
/// violated. /// violated.
PolicyViolation => "policy-violation", #[xml(name = "policy-violation")]
PolicyViolation,
/// The intended recipient is temporarily unavailable, undergoing /// The intended recipient is temporarily unavailable, undergoing
/// maintenance, etc.; the associated error type SHOULD be "wait". /// maintenance, etc.; the associated error type SHOULD be "wait".
RecipientUnavailable => "recipient-unavailable", #[xml(name = "recipient-unavailable")]
RecipientUnavailable,
/// The recipient or server is redirecting requests for this /// The recipient or server is redirecting requests for this
/// information to another entity, typically in a temporary fashion (as /// information to another entity, typically in a temporary fashion (as
@ -132,7 +152,13 @@ generate_element_enum!(
/// XML character data of the \<redirect/\> element (which MUST be a URI /// XML character data of the \<redirect/\> element (which MUST be a URI
/// or IRI with which the sender can communicate, typically an XMPP IRI /// or IRI with which the sender can communicate, typically an XMPP IRI
/// as specified in [XMPPURI](https://xmpp.org/rfcs/rfc5122.html)). /// as specified in [XMPPURI](https://xmpp.org/rfcs/rfc5122.html)).
Redirect => "redirect", #[xml(name = "redirect")]
Redirect {
/// The new address of the entity for which the error was returned,
/// if available.
#[xml(text(codec = EmptyAsNone))]
new_address: Option<String>,
},
/// The requesting entity is not authorized to access the requested /// The requesting entity is not authorized to access the requested
/// service because prior registration is necessary (examples of prior /// service because prior registration is necessary (examples of prior
@ -140,7 +166,8 @@ generate_element_enum!(
/// [XEP0045] and gateways to non-XMPP instant messaging services, /// [XEP0045] and gateways to non-XMPP instant messaging services,
/// which traditionally required registration in order to use the /// which traditionally required registration in order to use the
/// gateway [XEP0100]); the associated error type SHOULD be "auth". /// gateway [XEP0100]); the associated error type SHOULD be "auth".
RegistrationRequired => "registration-required", #[xml(name = "registration-required")]
RegistrationRequired,
/// A remote server or service specified as part or all of the JID of /// A remote server or service specified as part or all of the JID of
/// the intended recipient does not exist or cannot be resolved (e.g., /// the intended recipient does not exist or cannot be resolved (e.g.,
@ -148,7 +175,8 @@ generate_element_enum!(
/// fallback resolution fails, or A/AAAA lookups succeed but there is /// fallback resolution fails, or A/AAAA lookups succeed but there is
/// no response on the IANA-registered port 5269); the associated error /// no response on the IANA-registered port 5269); the associated error
/// type SHOULD be "cancel". /// type SHOULD be "cancel".
RemoteServerNotFound => "remote-server-not-found", #[xml(name = "remote-server-not-found")]
RemoteServerNotFound,
/// A remote server or service specified as part or all of the JID of /// A remote server or service specified as part or all of the JID of
/// the intended recipient (or needed to fulfill a request) was /// the intended recipient (or needed to fulfill a request) was
@ -160,16 +188,19 @@ generate_element_enum!(
/// SHOULD be "wait" (unless the error is of a more permanent nature, /// SHOULD be "wait" (unless the error is of a more permanent nature,
/// e.g., the remote server is found but it cannot be authenticated or /// e.g., the remote server is found but it cannot be authenticated or
/// it violates security policies). /// it violates security policies).
RemoteServerTimeout => "remote-server-timeout", #[xml(name = "remote-server-timeout")]
RemoteServerTimeout,
/// The server or recipient is busy or lacks the system resources /// The server or recipient is busy or lacks the system resources
/// necessary to service the request; the associated error type SHOULD /// necessary to service the request; the associated error type SHOULD
/// be "wait". /// be "wait".
ResourceConstraint => "resource-constraint", #[xml(name = "resource-constraint")]
ResourceConstraint,
/// The server or recipient does not currently provide the requested /// The server or recipient does not currently provide the requested
/// service; the associated error type SHOULD be "cancel". /// service; the associated error type SHOULD be "cancel".
ServiceUnavailable => "service-unavailable", #[xml(name = "service-unavailable")]
ServiceUnavailable,
/// The requesting entity is not authorized to access the requested /// The requesting entity is not authorized to access the requested
/// service because a prior subscription is necessary (examples of /// service because a prior subscription is necessary (examples of
@ -177,20 +208,22 @@ generate_element_enum!(
/// information as defined in [XMPPIM] and opt-in data feeds for XMPP /// information as defined in [XMPPIM] and opt-in data feeds for XMPP
/// publish-subscribe as defined in [XEP0060]); the associated error /// publish-subscribe as defined in [XEP0060]); the associated error
/// type SHOULD be "auth". /// type SHOULD be "auth".
SubscriptionRequired => "subscription-required", #[xml(name = "subscription-required")]
SubscriptionRequired,
/// The error condition is not one of those defined by the other /// The error condition is not one of those defined by the other
/// conditions in this list; any error type can be associated with this /// conditions in this list; any error type can be associated with this
/// condition, and it SHOULD NOT be used except in conjunction with an /// condition, and it SHOULD NOT be used except in conjunction with an
/// application-specific condition. /// application-specific condition.
UndefinedCondition => "undefined-condition", #[xml(name = "undefined-condition")]
UndefinedCondition,
/// The recipient or server understood the request but was not /// The recipient or server understood the request but was not
/// expecting it at this time (e.g., the request was out of order); the /// expecting it at this time (e.g., the request was out of order); the
/// associated error type SHOULD be "wait" or "modify". /// associated error type SHOULD be "wait" or "modify".
UnexpectedRequest => "unexpected-request", #[xml(name = "unexpected-request")]
UnexpectedRequest,
} }
);
type Lang = String; type Lang = String;
@ -211,11 +244,6 @@ pub struct StanzaError {
/// A protocol-specific extension for this error. /// A protocol-specific extension for this error.
pub other: Option<Element>, pub other: Option<Element>,
/// May include an alternate address if `defined_condition` is `Gone` or `Redirect`. It is
/// a Uniform Resource Identifier [URI] or Internationalized Resource Identifier [IRI] at
/// which the entity can be contacted, typically an XMPP IRI as specified in [XMPPURI]
pub alternate_address: Option<String>,
} }
impl MessagePayload for StanzaError {} impl MessagePayload for StanzaError {}
@ -243,7 +271,6 @@ impl StanzaError {
map map
}, },
other: None, other: None,
alternate_address: None,
} }
} }
} }
@ -263,7 +290,6 @@ impl TryFrom<Element> for StanzaError {
defined_condition: DefinedCondition::UndefinedCondition, defined_condition: DefinedCondition::UndefinedCondition,
texts: BTreeMap::new(), texts: BTreeMap::new(),
other: None, other: None,
alternate_address: None,
}; };
let mut defined_condition = None; let mut defined_condition = None;
@ -286,16 +312,7 @@ impl TryFrom<Element> for StanzaError {
} }
check_no_children!(child, "defined-condition"); check_no_children!(child, "defined-condition");
check_no_attributes!(child, "defined-condition"); check_no_attributes!(child, "defined-condition");
let condition = DefinedCondition::try_from(child.clone())?; defined_condition = Some(DefinedCondition::try_from(child.clone())?);
if condition == DefinedCondition::Gone || condition == DefinedCondition::Redirect {
stanza_error.alternate_address = child.nodes().find_map(|node| {
let Node::Text(text) = node else { return None };
Some(text.to_string())
});
}
defined_condition = Some(condition);
} else { } else {
if stanza_error.other.is_some() { if stanza_error.other.is_some() {
return Err( return Err(
@ -336,16 +353,16 @@ mod tests {
#[test] #[test]
fn test_size() { fn test_size() {
assert_size!(ErrorType, 1); assert_size!(ErrorType, 1);
assert_size!(DefinedCondition, 1); assert_size!(DefinedCondition, 16);
assert_size!(StanzaError, 104); assert_size!(StanzaError, 108);
} }
#[cfg(target_pointer_width = "64")] #[cfg(target_pointer_width = "64")]
#[test] #[test]
fn test_size() { fn test_size() {
assert_size!(ErrorType, 1); assert_size!(ErrorType, 1);
assert_size!(DefinedCondition, 1); assert_size!(DefinedCondition, 32);
assert_size!(StanzaError, 208); assert_size!(StanzaError, 216);
} }
#[test] #[test]
@ -446,10 +463,11 @@ mod tests {
.unwrap(); .unwrap();
let error = StanzaError::try_from(elem).unwrap(); let error = StanzaError::try_from(elem).unwrap();
assert_eq!(error.type_, ErrorType::Cancel); assert_eq!(error.type_, ErrorType::Cancel);
assert_eq!(error.defined_condition, DefinedCondition::Gone);
assert_eq!( assert_eq!(
error.alternate_address, error.defined_condition,
Some("xmpp:room@muc.example.org?join".to_string()) DefinedCondition::Gone {
new_address: Some("xmpp:room@muc.example.org?join".to_string()),
}
); );
} }
@ -465,8 +483,10 @@ mod tests {
.unwrap(); .unwrap();
let error = StanzaError::try_from(elem).unwrap(); let error = StanzaError::try_from(elem).unwrap();
assert_eq!(error.type_, ErrorType::Cancel); assert_eq!(error.type_, ErrorType::Cancel);
assert_eq!(error.defined_condition, DefinedCondition::Gone); assert_eq!(
assert_eq!(error.alternate_address, None); error.defined_condition,
DefinedCondition::Gone { new_address: None }
);
} }
#[test] #[test]
@ -481,10 +501,11 @@ mod tests {
.unwrap(); .unwrap();
let error = StanzaError::try_from(elem).unwrap(); let error = StanzaError::try_from(elem).unwrap();
assert_eq!(error.type_, ErrorType::Modify); assert_eq!(error.type_, ErrorType::Modify);
assert_eq!(error.defined_condition, DefinedCondition::Redirect);
assert_eq!( assert_eq!(
error.alternate_address, error.defined_condition,
Some("xmpp:characters@conference.example.org".to_string()) DefinedCondition::Redirect {
new_address: Some("xmpp:characters@conference.example.org".to_string()),
}
); );
} }
@ -500,7 +521,9 @@ mod tests {
.unwrap(); .unwrap();
let error = StanzaError::try_from(elem).unwrap(); let error = StanzaError::try_from(elem).unwrap();
assert_eq!(error.type_, ErrorType::Modify); assert_eq!(error.type_, ErrorType::Modify);
assert_eq!(error.defined_condition, DefinedCondition::Redirect); assert_eq!(
assert_eq!(error.alternate_address, None); error.defined_condition,
DefinedCondition::Redirect { new_address: None }
);
} }
} }