stylish_stringlike/text/
width.rs1use std::iter::Sum;
2use std::ops::{Add, AddAssign};
3
4#[derive(Copy, Clone, Debug, Eq, PartialEq)]
6pub enum Width {
7 Bounded(usize),
9 Unbounded,
11}
12
13impl Add for Width {
14 type Output = Width;
15 fn add(self, other: Self) -> Self::Output {
16 use Width::{Bounded, Unbounded};
17 match (self, other) {
18 (Unbounded, _) | (_, Unbounded) => Unbounded,
19 (Bounded(left), Bounded(right)) => Bounded(left + right),
20 }
21 }
22}
23
24impl AddAssign for Width {
25 fn add_assign(&mut self, other: Self) {
26 *self = *self + other;
27 }
28}
29
30impl Sum for Width {
31 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
32 iter.fold(Width::Bounded(0), |a, b| a + b)
33 }
34}
35
36pub trait HasWidth {
38 fn width(&self) -> Width;
49}
50
51impl<T> HasWidth for Option<T>
52where
53 T: HasWidth,
54{
55 fn width(&self) -> Width {
56 match self {
57 Some(t) => t.width(),
58 None => Width::Bounded(0),
59 }
60 }
61}
62
63pub trait BoundedWidth {
65 fn bounded_width(&self) -> usize;
76}
77
78impl BoundedWidth for String {
79 fn bounded_width(&self) -> usize {
80 unicode_width::UnicodeWidthStr::width(self.as_str())
81 }
82}
83
84impl HasWidth for String {
85 fn width(&self) -> Width {
86 Width::Bounded(self.bounded_width())
87 }
88}
89
90impl BoundedWidth for &str {
91 fn bounded_width(&self) -> usize {
92 unicode_width::UnicodeWidthStr::width(*self)
93 }
94}
95
96impl HasWidth for &str {
97 fn width(&self) -> Width {
98 Width::Bounded(self.bounded_width())
99 }
100}
101
102impl<T> BoundedWidth for Option<T>
103where
104 T: BoundedWidth,
105{
106 fn bounded_width(&self) -> usize {
107 match self {
108 Some(t) => t.bounded_width(),
109 None => 0,
110 }
111 }
112}
113
114#[cfg(test)]
115mod test {
116 use super::*;
117 #[test]
118 fn add_bounded() {
119 let actual = Width::Bounded(4) + Width::Bounded(6);
120 let expected = Width::Bounded(10);
121 assert_eq!(expected, actual);
122 }
123 #[test]
124 fn add_bound_unbound() {
125 let actual = Width::Bounded(4) + Width::Unbounded;
126 let expected = Width::Unbounded;
127 assert_eq!(expected, actual);
128 }
129 #[test]
130 fn add_unbound_bound() {
131 let actual = Width::Unbounded + Width::Bounded(4);
132 let expected = Width::Unbounded;
133 assert_eq!(expected, actual);
134 }
135 #[test]
136 fn add_bound_bound() {
137 let actual = Width::Unbounded + Width::Unbounded;
138 let expected = Width::Unbounded;
139 assert_eq!(expected, actual);
140 }
141 #[test]
142 fn sum() {
143 let v = vec![Width::Bounded(5), Width::Bounded(6), Width::Bounded(7)];
144 let actual: Width = v.iter().cloned().sum();
145 let expected = Width::Bounded(18);
146 assert_eq!(expected, actual);
147 }
148 #[test]
149 fn add_assign() {
150 let mut actual = Width::Bounded(1);
151 actual += Width::Bounded(4);
152 let expected = Width::Bounded(5);
153 assert_eq!(expected, actual);
154 }
155}