message: Add getters for the best body per language list.

Emmanuel Gil Peyrot created

Change summary

src/message.rs | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 91 insertions(+)

Detailed changes

src/message.rs 🔗

@@ -146,6 +146,43 @@ impl Message {
             payloads: vec!(),
         }
     }
+
+    fn get_best<'a, T>(map: &'a BTreeMap<Lang, T>, preferred_langs: Vec<&str>) -> Option<(Lang, &'a T)> {
+        if map.is_empty() {
+            return None;
+        }
+        for lang in preferred_langs {
+            if map.contains_key(lang) {
+                return Some((Lang::from(lang), &map[lang]));
+            }
+        }
+        if map.contains_key("") {
+            return Some((Lang::new(), &map[""]));
+        }
+        map.iter().map(|(lang, body)| (lang.clone(), body)).next()
+    }
+
+    /// Returns the best matching body from a list of languages.
+    ///
+    /// For instance, if a message contains both an xml:lang='de', an xml:lang='fr' and an English
+    /// body without an xml:lang attribute, and you pass ["fr", "en"] as your preferred languages,
+    /// `Some(("fr", the_second_body))` will be returned.
+    ///
+    /// If no body matches, an undefined body will be returned.
+    pub fn get_best_body(&self, preferred_langs: Vec<&str>) -> Option<(Lang, &Body)> {
+        Message::get_best::<Body>(&self.bodies, preferred_langs)
+    }
+
+    /// Returns the best matching subject from a list of languages.
+    ///
+    /// For instance, if a message contains both an xml:lang='de', an xml:lang='fr' and an English
+    /// subject without an xml:lang attribute, and you pass ["fr", "en"] as your preferred
+    /// languages, `Some(("fr", the_second_subject))` will be returned.
+    ///
+    /// If no subject matches, an undefined subject will be returned.
+    pub fn get_best_subject(&self, preferred_langs: Vec<&str>) -> Option<(Lang, &Subject)> {
+        Message::get_best::<Subject>(&self.subjects, preferred_langs)
+    }
 }
 
 impl TryFrom<Element> for Message {
@@ -281,6 +318,12 @@ mod tests {
         let message = Message::try_from(elem).unwrap();
         assert_eq!(message.bodies[""], Body::from_str("Hello world!").unwrap());
 
+        {
+            let (lang, body) = message.get_best_body(vec!("en")).unwrap();
+            assert_eq!(lang, "");
+            assert_eq!(body, &Body::from_str("Hello world!").unwrap());
+        }
+
         let elem2 = message.into();
         assert!(elem1.compare_to(&elem2));
     }
@@ -307,10 +350,58 @@ mod tests {
         let message = Message::try_from(elem).unwrap();
         assert_eq!(message.subjects[""], Subject::from_str("Hello world!").unwrap());
 
+        {
+            let (lang, subject) = message.get_best_subject(vec!("en")).unwrap();
+            assert_eq!(lang, "");
+            assert_eq!(subject, &Subject::from_str("Hello world!").unwrap());
+        }
+
         let elem2 = message.into();
         assert!(elem1.compare_to(&elem2));
     }
 
+    #[test]
+    fn get_best_body() {
+        #[cfg(not(feature = "component"))]
+        let elem: Element = "<message xmlns='jabber:client' to='coucou@example.org' type='chat'><body xml:lang='de'>Hallo Welt!</body><body xml:lang='fr'>Salut le monde !</body><body>Hello world!</body></message>".parse().unwrap();
+        #[cfg(feature = "component")]
+        let elem: Element = "<message xmlns='jabber:component:accept' to='coucou@example.org' type='chat'><body>Hello world!</body></message>".parse().unwrap();
+        let message = Message::try_from(elem).unwrap();
+
+        // Tests basic feature.
+        {
+            let (lang, body) = message.get_best_body(vec!("fr")).unwrap();
+            assert_eq!(lang, "fr");
+            assert_eq!(body, &Body::from_str("Salut le monde !").unwrap());
+        }
+
+        // Tests order.
+        {
+            let (lang, body) = message.get_best_body(vec!("en", "de")).unwrap();
+            assert_eq!(lang, "de");
+            assert_eq!(body, &Body::from_str("Hallo Welt!").unwrap());
+        }
+
+        // Tests fallback.
+        {
+            let (lang, body) = message.get_best_body(vec!()).unwrap();
+            assert_eq!(lang, "");
+            assert_eq!(body, &Body::from_str("Hello world!").unwrap());
+        }
+
+        // Tests fallback.
+        {
+            let (lang, body) = message.get_best_body(vec!("ja")).unwrap();
+            assert_eq!(lang, "");
+            assert_eq!(body, &Body::from_str("Hello world!").unwrap());
+        }
+
+        let message = Message::new(None);
+
+        // Tests without a body.
+        assert_eq!(message.get_best_body(vec!("ja")), None);
+    }
+
     #[test]
     fn test_attention() {
         #[cfg(not(feature = "component"))]