1pub trait StrUtils {
2 fn split_first_whitespace(&self) -> (&str, &str);
3
4 fn is_only_whitespace(&self) -> bool;
5}
6
7impl StrUtils for str {
8 fn split_first_whitespace(&self) -> (&str, &str) {
11 for (i, c) in self.char_indices() {
12 if c.is_ascii_whitespace() {
13 return (&self[..i], &self[i + c.len_utf8()..]);
14 }
15 }
16 return (self, "");
17 }
18
19 fn is_only_whitespace(&self) -> bool {
20 self.chars().all(|c| c.is_ascii_whitespace())
21 }
22}
23
24#[macro_export]
27macro_rules! include_test_file {
28 ($filename:expr) => {
29 include_str!(concat!("../resources/tests/", $filename))
30 };
31}
32
33#[macro_export]
35macro_rules! recursive_tokenize {
36 ($tail:expr) => {
37 Lexer::tokenize($tail)
38 };
39 ($tail:expr, $ret:expr) => {
40 if $tail.len() > 0 {
41 if let Ok(tail_tokens) = Lexer::tokenize($tail) {
42 for token in tail_tokens {
44 $ret.push(token);
45 }
46 }
47 }
48 };
49}
50
51#[macro_export]
52macro_rules! recursive_tokenize_with_init {
53 ($init:expr, $tail:expr) => {{
54 let mut ret = vec![$init];
55 recursive_tokenize!($tail, ret);
56 return Ok(ret);
57 }};
58}
59
60#[cfg(test)]
61mod test {
62 use super::*;
63
64 #[test]
65 fn test_split_first_whitespace() {
66 let text = r"\b I'm a bold string";
67 let split = text.split_first_whitespace();
68 assert_eq!(split, (r"\b", r"I'm a bold string"));
69 }
70
71 #[test]
72 fn test_split_first_whitespace_with_utf8() {
73 let text = "\\a\u{a0}";
74 let split = text.split_first_whitespace();
75 assert_eq!(split, (text, ""));
76 }
77}