1pub fn wrap(value: &str) -> String {
2 const SOFT_WIDTH: usize = 75;
3 const HARD_WIDTH: usize = 1000;
4 wrap_impl(value, SOFT_WIDTH, HARD_WIDTH)
5}
6
7fn wrap_impl(value: &str, soft_width: usize, hard_width: usize) -> String {
13 let mut result = String::new();
14 let mut line = String::new();
15
16 for word in value.split_ascii_whitespace() {
17 if line.len() + word.len() < soft_width {
18 if !line.is_empty() {
19 line.push(' ');
20 }
21 line.push_str(word);
22 continue;
23 }
24
25 if !line.is_empty() {
29 if !result.is_empty() {
30 result.push('\t');
32 }
33 result.push_str(&line);
34 result.push_str("\r\n");
35 line.clear();
36 }
37
38 if word.len() <= hard_width {
40 line.push_str(word);
41 } else {
42 for c in word.chars() {
43 line.push(c);
44 if line.len() >= hard_width {
45 if !result.is_empty() {
46 result.push('\t');
47 }
48 result.push_str(&line);
49 result.push_str("\r\n");
50 line.clear();
51 continue;
52 }
53 }
54 }
55 }
56
57 if !line.is_empty() {
58 if !result.is_empty() {
59 result.push('\t');
60 }
61 result.push_str(&line);
62 }
63
64 result
65}
66
67#[cfg(test)]
68mod test {
69 use super::*;
70
71 #[test]
72 fn wrapping() {
73 for (input, expect) in [
74 ("foo", "foo"),
75 ("hi there", "hi there"),
76 ("hello world", "hello\r\n\tworld"),
77 (
78 "hello world foo bar baz woot woot",
79 "hello\r\n\tworld foo\r\n\tbar baz\r\n\twoot woot",
80 ),
81 (
82 "hi there breakmepleaseIamtoolong",
83 "hi there\r\n\tbreakmepleaseIa\r\n\tmtoolong",
84 ),
85 ] {
86 let wrapped = wrap_impl(input, 10, 15);
87 k9::assert_equal!(
88 wrapped,
89 expect,
90 "input: '{input}' should produce '{expect}'"
91 );
92 }
93 }
94}