1pub fn truncate_str(input: &str, max_len: usize) -> String {
8 if input.len() <= max_len {
9 return input.to_string();
10 }
11 let mut end = max_len;
12 while end > 0 && !input.is_char_boundary(end) {
13 end -= 1;
14 }
15 format!("{}…", &input[..end])
16}
17
18#[cfg(test)]
19mod tests {
20 use super::truncate_str;
21
22 #[test]
23 fn short_input_unchanged() {
24 assert_eq!(truncate_str("hi", 10), "hi");
25 }
26
27 #[test]
28 fn ascii_truncates_with_ellipsis() {
29 let out = truncate_str("abcdefghij", 5);
30 assert_eq!(out, "abcde…");
31 }
32
33 #[test]
34 fn does_not_panic_on_multibyte_boundary() {
35 let out = truncate_str("日本語テキスト", 4);
38 assert_eq!(out, "日…");
40 }
41
42 #[test]
43 fn handles_emoji() {
44 let out = truncate_str("🦀🦀🦀", 2);
46 assert_eq!(out, "…");
47 }
48
49 #[test]
50 fn zero_max_len_returns_just_ellipsis() {
51 assert_eq!(truncate_str("hello", 0), "…");
52 }
53}