about summary refs log tree commit diff
path: root/src/description.rs
diff options
context:
space:
mode:
authorGriffin Smith <root@gws.fyi>2019-07-29T02·31-0400
committerGriffin Smith <root@gws.fyi>2019-07-29T02·31-0400
commit34b20b7786a8f6753bb449425772958e0285c385 (patch)
treee8781db1c3bed3f8897f40fb201c40b6f1d28bac /src/description.rs
parentba7bec9a3e36eaf2af65677b02884172241d1b24 (diff)
Add functions for making sentences from lists
This seems like something I keep having to write
Diffstat (limited to 'src/description.rs')
-rw-r--r--src/description.rs93
1 files changed, 93 insertions, 0 deletions
diff --git a/src/description.rs b/src/description.rs
new file mode 100644
index 000000000000..4c553c746d91
--- /dev/null
+++ b/src/description.rs
@@ -0,0 +1,93 @@
+use crate::entities::Describe;
+
+pub fn list_to_sentence(lst: &Vec<String>) -> String {
+    let mut buf = String::with_capacity(
+        lst.iter()
+            .map(|e| e.len() + 2usize /* ", " */)
+            .sum::<usize>()
+            + if lst.len() >= 3 {
+                3usize /* "and" */
+            } else {
+                0usize
+            },
+    );
+
+    match lst.len() {
+        0 => {}
+        1 => buf.push_str(&lst[0]),
+        2 => {
+            buf.push_str(&lst[0]);
+            buf.push_str(" and ");
+            buf.push_str(&lst[1]);
+        }
+        _ => {
+            for desc in &lst[..lst.len() - 1] {
+                buf.push_str(desc);
+                buf.push_str(", ");
+            }
+            buf.push_str("and ");
+            buf.push_str(&lst[lst.len() - 1]);
+        }
+    }
+
+    buf
+}
+
+pub fn describe_list<A: Describe>(lst: &Vec<A>) -> String {
+    list_to_sentence(
+        &lst.iter().map(|e| e.description()).collect::<Vec<String>>(),
+    )
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use proptest::prelude::*;
+    use proptest_derive::Arbitrary;
+
+    #[derive(Debug, Arbitrary)]
+    struct Description(String);
+
+    impl Describe for Description {
+        fn description(&self) -> String {
+            self.0.clone()
+        }
+    }
+
+    proptest! {
+        #[test]
+        fn test_describe_list_includes_all_descriptions(
+            descriptions: Vec<Description>
+        ) {
+            let res = describe_list(&descriptions);
+            for Description(desc) in descriptions {
+                assert!(res.contains(&desc));
+            }
+        }
+    }
+
+    #[test]
+    fn test_describe_list() {
+        assert_eq!(
+            describe_list(&vec![Description("one".to_string())]),
+            "one".to_string()
+        );
+
+        assert_eq!(
+            describe_list(&vec![
+                Description("one".to_string()),
+                Description("two".to_string())
+            ]),
+            "one and two".to_string()
+        );
+
+        assert_eq!(
+            describe_list(&vec![
+                Description("one".to_string()),
+                Description("two".to_string()),
+                Description("three".to_string())
+            ]),
+            "one, two, and three".to_string()
+        );
+    }
+}