ellipse/lib.rs
1//! Truncate and ellipse strings in a human-friendly way.
2//!
3//! Uses unicode extended grapheme clusters.
4//!
5//! # Example
6//! ```
7//! use ellipse::Ellipse;
8//!
9//! let input = "🇩🇪🇬🇧🇮🇹🇫🇷";
10//! assert_eq!(&input.truncate_ellipse(2), "🇩🇪🇬🇧...");
11//! ```
12
13use std::borrow::Cow;
14use unicode_segmentation::UnicodeSegmentation;
15
16/// Truncate and ellipse strings in a human-friendly way.
17///
18/// # Example
19/// ```
20/// use ellipse::Ellipse;
21///
22/// let input = "🇩🇪🇬🇧🇮🇹🇫🇷";
23/// assert_eq!(&input.truncate_ellipse(2), "🇩🇪🇬🇧...");
24/// ```
25pub trait Ellipse {
26 type Output;
27
28 /// Truncate to a length of `len` extended grapheme clusters and place the given
29 /// ellipse string at the end when truncating.
30 ///
31 /// Truncating to a length of 0 will yield the empty element without an
32 /// attached ellipsis.
33 fn truncate_ellipse_with(&self, len: usize, ellipse: &str) -> Self::Output;
34
35 /// Truncate to a length of `len` extended grapheme clusters and add `...` at
36 /// the end of the string when truncating.
37 ///
38 /// Truncating to a length of 0 will yield the empty element without an
39 /// attached ellipsis.
40 fn truncate_ellipse(&self, len: usize) -> Self::Output {
41 self.truncate_ellipse_with(len, "...")
42 }
43}
44
45impl<'a> Ellipse for &'a str {
46 type Output = Cow<'a, str>;
47
48 fn truncate_ellipse_with(&self, len: usize, ellipse: &str) -> Self::Output {
49 if self.graphemes(true).count() <= len {
50 return Cow::Borrowed(self);
51 } else if len == 0 {
52 return Cow::Borrowed("");
53 }
54
55 let result = self
56 .graphemes(true)
57 .take(len)
58 .chain(ellipse.graphemes(true))
59 .collect();
60 Cow::Owned(result)
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67
68 #[test]
69 fn smoke() {
70 assert_eq!(&"Hello, World!".truncate_ellipse(3), "Hel...",);
71 }
72
73 #[test]
74 fn ellipse_with() {
75 assert_eq!(&"Hello, World!".truncate_ellipse_with(3, "---"), "Hel---");
76 }
77
78 #[test]
79 fn truncate_to_empty() {
80 assert_eq!(&"Hello, World!".truncate_ellipse(0), "");
81 }
82
83 #[test]
84 fn weird_chars() {
85 assert_eq!(
86 &"🇩🇪🇬🇧🇮🇹🇫🇷".truncate_ellipse(2),
87 "🇩🇪🇬🇧..."
88 );
89 }
90}