parsers: port enums over to derive macros

Jonas Schäfer created

Change summary

parsers/ChangeLog           |   5 
parsers/src/chatstates.rs   |  46 ++-
parsers/src/iq.rs           |   8 
parsers/src/mood.rs         | 434 +++++++++++++++++++++++---------------
parsers/src/sasl.rs         |  93 ++++---
parsers/src/sm.rs           |   4 
parsers/src/stanza_error.rs | 401 +++++++++++++++++++----------------
7 files changed, 563 insertions(+), 428 deletions(-)

Detailed changes

parsers/ChangeLog 🔗

@@ -1,5 +1,10 @@
 Version NEXT:
 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:
         - Stream Features (RFC 6120) (!400)
 

parsers/src/chatstates.rs 🔗

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

parsers/src/iq.rs 🔗

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

parsers/src/mood.rs 🔗

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

parsers/src/sasl.rs 🔗

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

parsers/src/sm.rs 🔗

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

parsers/src/stanza_error.rs 🔗

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