1pub trait Blank {
5 fn is_blank(&self) -> bool;
7 fn is_present(&self) -> bool {
9 !self.is_blank()
10 }
11}
12
13impl Blank for str {
14 fn is_blank(&self) -> bool {
15 self.trim().is_empty()
16 }
17}
18
19impl<T: Blank + ?Sized> Blank for &T {
20 fn is_blank(&self) -> bool {
21 (**self).is_blank()
22 }
23}
24
25impl Blank for String {
26 fn is_blank(&self) -> bool {
27 self.as_str().is_blank()
28 }
29}
30
31impl<T: Blank> Blank for Option<T> {
32 fn is_blank(&self) -> bool {
33 self.as_ref().map(Blank::is_blank).unwrap_or(true)
34 }
35}
36
37impl<T> Blank for Vec<T> {
38 fn is_blank(&self) -> bool {
39 self.is_empty()
40 }
41}
42
43pub trait StringExt {
45 fn truncate_chars(&self, len: usize) -> String;
47}
48
49impl StringExt for str {
50 fn truncate_chars(&self, len: usize) -> String {
51 if self.chars().count() <= len {
52 self.to_string()
53 } else {
54 let kept: String = self.chars().take(len.saturating_sub(1)).collect();
55 format!("{kept}…")
56 }
57 }
58}