1#[derive(Debug)]
10pub struct GraphemeBytesIter<'a> {
11 source: &'a str,
12 offset: usize,
13 grapheme_count: usize,
14}
15impl<'a> GraphemeBytesIter<'a> {
16 pub fn new(source: &'a str) -> GraphemeBytesIter<'a> {
18 GraphemeBytesIter {
19 source: source,
20 offset: 0,
21 grapheme_count: 0,
22 }
23 }
24}
25impl<'a> Iterator for GraphemeBytesIter<'a> {
26 type Item = &'a [u8];
27
28 fn next(&mut self) -> Option<&'a [u8]> {
29 let mut result: Option<&[u8]> = None;
30 let mut idx = self.offset;
31 for _ in self.offset..self.source.len() {
32 idx += 1;
33 if self.offset < self.source.len() {
34 if self.source.is_char_boundary(idx) {
35 let slice: &[u8] = self.source[self.offset..idx].as_bytes();
36
37 self.grapheme_count += 1;
38 self.offset = idx;
39
40 result = Some(slice);
41 break
42 }
43 }
44 }
45 result
46 }
47}
48impl<'a> ExactSizeIterator for GraphemeBytesIter<'a> {
49 fn len(&self) -> usize {
50 self.source.chars().count()
51 }
52}
53pub trait ToGraphemeBytesIter<'a> {
55 fn grapheme_bytes_iter(&'a self) -> GraphemeBytesIter<'a>;
71}
72impl<'a> ToGraphemeBytesIter<'a> for str {
73 fn grapheme_bytes_iter(&'a self) -> GraphemeBytesIter<'a> {
74 GraphemeBytesIter::new(&self)
75 }
76}
77
78pub trait Squeeze {
80 fn squeeze(&self, targets: &'static str) -> String;
92}
93impl Squeeze for str {
94 fn squeeze(&self, targets: &'static str) -> String {
95 let mut output = Vec::<u8>::with_capacity(self.len());
96 let everything: bool = targets.is_empty();
97 let chars = targets.grapheme_bytes_iter().collect::<Vec<&[u8]>>();
98 let mut last: &[u8] = &[0];
99 for character in self.grapheme_bytes_iter() {
100 if last != character {
101 output.extend_from_slice(character);
102 } else if !(everything || chars.contains(&character)) {
103 output.extend_from_slice(character);
104 }
105 last = character;
106 }
107 String::from_utf8(output).expect("squeeze failed to render String!")
108 }
109}
110
111pub trait Justify {
113 fn justify_line(&self, width: usize) -> String;
125}
126
127impl Justify for str {
128 fn justify_line(&self, width: usize) -> String {
129 if self.is_empty() { return format!("{}", self) };
130 let trimmed = self.trim() ;
131 let len = trimmed.chars().count();
132 if len >= width { return self.to_string(); };
133 let difference = width - len;
134 let iter = trimmed.split_whitespace();
135 let spaces = iter.count() - 1;
136 let mut iter = trimmed.split_whitespace().peekable();
137 if spaces == 0 { return self.to_string(); }
138 let mut obj = String::with_capacity(trimmed.len() + spaces);
139
140 let div = difference / spaces;
141 let mut remainder = difference % spaces;
142
143 while let Some(x) = iter.next() {
144 obj.push_str( x );
145 let val = if remainder > 0 {
146 remainder = remainder - 1;
147 div + 1
148 } else { div };
149 for _ in 0..val+1 {
150 if let Some(_) = iter.peek() { obj.push_str( " " );
152 }
153 }
154 }
155 obj
156 }
157}
158
159pub trait SubstMarks {
161 fn subst_marks(&self, marks: Vec<usize>, chr: &'static str) -> String;
173}
174impl SubstMarks for str {
175 fn subst_marks(&self, marks: Vec<usize>, chr: &'static str) -> String {
176 let mut output = Vec::<u8>::with_capacity(self.len());
177 let mut count = 0;
178 let mut last = 0;
179 for i in 0..self.len() {
180 let idx = i + 1;
181 if self.is_char_boundary(idx) {
182 if marks.contains(&count) {
183 count += 1;
184 last = idx;
185 output.extend_from_slice(chr.as_bytes());
186 continue
187 }
188
189 let slice: &[u8] = self[last..idx].as_bytes();
190 output.extend_from_slice(slice);
191
192 count += 1;
193 last = idx
194 }
195 }
196 String::from_utf8(output).expect("subst_marks failed to render String!")
197 }
198}
199
200pub trait AfterWhitespace {
202 fn seek_end_of_whitespace(&self, offset: usize) -> Option<usize>;
215}
216impl AfterWhitespace for str {
217 fn seek_end_of_whitespace(&self, offset: usize) -> Option<usize> {
218 if self.len() < offset { return None; };
219 let mut seeker = self[offset..self.len()].chars();
220 let mut val = None;
221 let mut indx = 0;
222 while let Some(x) = seeker.next() {
223 if x.ne(&" ".chars().next().unwrap()) {
224 val = Some(indx);
225 break;
226 }
227 indx += 1;
228 }
229 val
230 }
231}
232
233pub trait WordWrap {
235 fn word_wrap(&self, width: usize) -> String;
254}
255impl WordWrap for &'static str {
258 fn word_wrap(&self, width: usize) -> String {
259 let mut markers = vec![];
260 fn wordwrap(t: &'static str, chunk: usize, offset: usize, mrkrs: &mut Vec<usize>) -> String {
261 match t[offset..*vec![offset+chunk,t.len()].iter().min().unwrap()].rfind("\n") {
262 None => {
263 match t[offset..*vec![offset+chunk,t.len()].iter().min().unwrap()].rfind(" ") {
264 Some(x) => {
265 let mut eows = x; if offset+chunk < t.len() { match t.seek_end_of_whitespace(offset+x) {
268 Some(a) => {
269 if a.ne(&0) {
270 eows = x+a-1;
271 }
272 },
273 None => {},
274 }
275 }
276 if offset+chunk < t.len() { if !["\n".chars().next().unwrap(), " ".chars().next().unwrap()].contains(
278 &t[offset+eows+1..offset+eows+2].chars().next().unwrap()
279 ) {
280 mrkrs.push(offset+eows)
281 }
282 };
283 wordwrap(t, chunk, offset+eows+1, mrkrs)
284 },
285 None => {
286 if offset+chunk < t.len() { wordwrap(t, chunk, offset+1, mrkrs) } else {
289 use string::SubstMarks;
290
291 return t.subst_marks(mrkrs.to_vec(), "\n")
292 }
293 },
294 }
295 },
296 Some(x) => {
297 wordwrap(t, chunk, offset+x+1, mrkrs)
298 },
299 }
300 };
301 wordwrap(self, width+1, 0, &mut markers)
302 }
303}