diff --git a/parsers/ChangeLog b/parsers/ChangeLog index 57fc0068d06cc333609421187e58191fb493f545..2bfb185e1902de2061772e2884cdad614dd9661a 100644 --- a/parsers/ChangeLog +++ b/parsers/ChangeLog @@ -1,8 +1,10 @@ Version xxx: xxx + * New parsers/serialisers: + - Message Reactions (XEP-0444) * Improvements: - - muc::user::Item: Added with_ helpers - - Correct cargo doc warnings + - muc::user::Item: Added with_ helpers + - Correct cargo doc warnings Version 0.19.2: 2022-12-17 Maxime β€œpep” Buquet @@ -17,10 +19,10 @@ Version 0.19.2: Version 0.19.1: 2022-07-13 Emmanuel Gil Peyrot * New parsers/serialisers: - - Add In-Band Real Time Text support - - Add OMEMO support + - Add In-Band Real Time Text support + - Add OMEMO support * Improvements: - - bookmarks 2: uncomment test + - bookmarks 2: uncomment test Version 0.19.0: 2022-03-07 Emmanuel Gil Peyrot diff --git a/parsers/src/lib.rs b/parsers/src/lib.rs index db45509bb208f5810ffc9e3b70f5376e69cfbdbb..6919a9bd3607dca37b764fccb895ddca2cbff78d 100644 --- a/parsers/src/lib.rs +++ b/parsers/src/lib.rs @@ -239,3 +239,6 @@ pub mod occupant_id; /// XEP-0441: Message Archive Management Preferences pub mod mam_prefs; + +/// XEP-0444: Message Reactions +pub mod reactions; diff --git a/parsers/src/ns.rs b/parsers/src/ns.rs index 5cde63cb39ef8b8619e5448399d4b7ad02295d4f..e2304e5973da4c7546d14b9d9b742925c3a648c3 100644 --- a/parsers/src/ns.rs +++ b/parsers/src/ns.rs @@ -272,6 +272,9 @@ pub const BOOKMARKS2_COMPAT_PEP: &str = "urn:xmpp:bookmarks:1#compat-pep"; /// XEP-0421: Anonymous unique occupant identifiers for MUCs pub const OID: &str = "urn:xmpp:occupant-id:0"; +/// XEP-0444: Message Reactions +pub const REACTIONS: &str = "urn:xmpp:reactions:0"; + /// Alias for the main namespace of the stream, that is "jabber:client" when /// the component feature isn’t enabled. #[cfg(not(feature = "component"))] diff --git a/parsers/src/reactions.rs b/parsers/src/reactions.rs new file mode 100644 index 0000000000000000000000000000000000000000..dd241e40e181df7f4d0868372fbb3af99d03d33f --- /dev/null +++ b/parsers/src/reactions.rs @@ -0,0 +1,96 @@ +// Copyright (c) 2022 Emmanuel Gil Peyrot +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +use crate::message::MessagePayload; +use crate::util::helpers::Text; + +generate_element!( + /// Container for a set of reactions. + Reactions, "reactions", REACTIONS, + attributes: [ + /// The id of the message these reactions apply to. + id: Required = "id", + ], + children: [ + /// The list of reactions. + reactions: Vec = ("reaction", REACTIONS) => Reaction, + ] +); + +impl MessagePayload for Reactions {} + +generate_element!( + /// One emoji reaction. + Reaction, "reaction", REACTIONS, + text: ( + /// The text of this reaction. + emoji: Text + ) +); + +#[cfg(test)] +mod tests { + use super::*; + use crate::Element; + use std::convert::{TryFrom, TryInto}; + + #[cfg(target_pointer_width = "32")] + #[test] + fn test_size() { + assert_size!(Reactions, 24); + assert_size!(Reaction, 12); + } + + #[cfg(target_pointer_width = "64")] + #[test] + fn test_size() { + assert_size!(Reactions, 48); + assert_size!(Reaction, 24); + } + + #[test] + fn test_empty() { + let elem: Element = "" + .parse() + .unwrap(); + let elem2 = elem.clone(); + let reactions = Reactions::try_from(elem2).unwrap(); + assert_eq!(reactions.id, "foo"); + assert_eq!(reactions.reactions.len(), 0); + } + + #[test] + fn test_multi() { + let elem: Element = + "πŸ‘‹πŸ’" + .parse() + .unwrap(); + let elem2 = elem.clone(); + let reactions = Reactions::try_from(elem2).unwrap(); + assert_eq!(reactions.id, "foo"); + assert_eq!(reactions.reactions.len(), 2); + let [hand, turtle]: [Reaction; 2] = reactions.reactions.try_into().unwrap(); + assert_eq!(hand.emoji, "πŸ‘‹"); + assert_eq!(turtle.emoji, "🐒"); + } + + #[test] + fn test_zwj_emoji() { + let elem: Element = + "πŸ‘©πŸΎβ€β€οΈβ€πŸ‘©πŸΌ" + .parse() + .unwrap(); + let elem2 = elem.clone(); + let mut reactions = Reactions::try_from(elem2).unwrap(); + assert_eq!(reactions.id, "foo"); + assert_eq!(reactions.reactions.len(), 1); + let reaction = reactions.reactions.pop().unwrap(); + assert_eq!( + reaction.emoji, + "\u{1F469}\u{1F3FE}\u{200D}\u{2764}\u{FE0F}\u{200D}\u{1F469}\u{1F3FC}" + ); + } +}