1 | pub fn skip(mut s: &str) -> &str { |
2 | 'skip: while !s.is_empty() { |
3 | let byte = s.as_bytes()[0]; |
4 | if byte == b'/' { |
5 | if s.starts_with("//" ) |
6 | && (!s.starts_with("///" ) || s.starts_with("////" )) |
7 | && !s.starts_with("//!" ) |
8 | { |
9 | if let Some(i) = s.find(' \n' ) { |
10 | s = &s[i + 1..]; |
11 | continue; |
12 | } else { |
13 | return "" ; |
14 | } |
15 | } else if s.starts_with("/**/" ) { |
16 | s = &s[4..]; |
17 | continue; |
18 | } else if s.starts_with("/*" ) |
19 | && (!s.starts_with("/**" ) || s.starts_with("/***" )) |
20 | && !s.starts_with("/*!" ) |
21 | { |
22 | let mut depth = 0; |
23 | let bytes = s.as_bytes(); |
24 | let mut i = 0; |
25 | let upper = bytes.len() - 1; |
26 | while i < upper { |
27 | if bytes[i] == b'/' && bytes[i + 1] == b'*' { |
28 | depth += 1; |
29 | i += 1; // eat '*' |
30 | } else if bytes[i] == b'*' && bytes[i + 1] == b'/' { |
31 | depth -= 1; |
32 | if depth == 0 { |
33 | s = &s[i + 2..]; |
34 | continue 'skip; |
35 | } |
36 | i += 1; // eat '/' |
37 | } |
38 | i += 1; |
39 | } |
40 | return s; |
41 | } |
42 | } |
43 | match byte { |
44 | b' ' | 0x09..=0x0d => { |
45 | s = &s[1..]; |
46 | continue; |
47 | } |
48 | b if b <= 0x7f => {} |
49 | _ => { |
50 | let ch = s.chars().next().unwrap(); |
51 | if is_whitespace(ch) { |
52 | s = &s[ch.len_utf8()..]; |
53 | continue; |
54 | } |
55 | } |
56 | } |
57 | return s; |
58 | } |
59 | s |
60 | } |
61 | |
62 | fn is_whitespace(ch: char) -> bool { |
63 | // Rust treats left-to-right mark and right-to-left mark as whitespace |
64 | ch.is_whitespace() || ch == ' \u{200e}' || ch == ' \u{200f}' |
65 | } |
66 | |