1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use std::iter::Peekable;
use std::slice::Split;
pub fn unindent(s: &str) -> String {
let bytes = s.as_bytes();
let unindented = unindent_bytes(bytes);
String::from_utf8(unindented).unwrap()
}
pub fn unindent_bytes(s: &[u8]) -> Vec<u8> {
let ignore_first_line = s.starts_with(b"\n") || s.starts_with(b"\r\n");
let spaces = s
.lines()
.skip(1)
.filter_map(count_spaces)
.min()
.unwrap_or(0);
let mut result = Vec::with_capacity(s.len());
for (i, line) in s.lines().enumerate() {
if i > 1 || (i == 1 && !ignore_first_line) {
result.push(b'\n');
}
if i == 0 {
result.extend_from_slice(line);
} else if line.len() > spaces {
result.extend_from_slice(&line[spaces..]);
}
}
result
}
pub trait Unindent {
type Output;
fn unindent(&self) -> Self::Output;
}
impl Unindent for str {
type Output = String;
fn unindent(&self) -> Self::Output {
unindent(self)
}
}
impl Unindent for String {
type Output = String;
fn unindent(&self) -> Self::Output {
unindent(self)
}
}
impl Unindent for [u8] {
type Output = Vec<u8>;
fn unindent(&self) -> Self::Output {
unindent_bytes(self)
}
}
impl<'a, T: ?Sized + Unindent> Unindent for &'a T {
type Output = T::Output;
fn unindent(&self) -> Self::Output {
(**self).unindent()
}
}
fn count_spaces(line: &[u8]) -> Option<usize> {
for (i, ch) in line.iter().enumerate() {
if *ch != b' ' && *ch != b'\t' {
return Some(i);
}
}
None
}
trait BytesExt {
fn lines(&self) -> Lines;
}
impl BytesExt for [u8] {
fn lines(&self) -> Lines {
fn is_newline(b: &u8) -> bool {
*b == b'\n'
}
let bytestring = if self.starts_with(b"\r\n") {
&self[1..]
} else {
self
};
Lines {
split: bytestring.split(is_newline as fn(&u8) -> bool).peekable(),
}
}
}
struct Lines<'a> {
split: Peekable<Split<'a, u8, fn(&u8) -> bool>>,
}
impl<'a> Iterator for Lines<'a> {
type Item = &'a [u8];
fn next(&mut self) -> Option<Self::Item> {
match self.split.next() {
None => None,
Some(fragment) => {
if fragment.is_empty() && self.split.peek().is_none() {
None
} else {
Some(fragment)
}
}
}
}
}