1pub fn to_snake_case(s: &str) -> String {
2 let mut snake = String::new();
3 let chars: Vec<char> = s.chars().collect();
4 for (i, c) in chars.iter().enumerate() {
5 if c.is_whitespace() {
6 snake.push('_');
7 continue;
8 }
9
10 if c.is_uppercase() && i != 0 && chars[i - 1] != ' ' {
11 snake.push('_');
12 }
13 snake.extend(c.to_lowercase());
14 }
15 snake
16}
17
18pub fn to_camel_case(s: &str) -> String {
20 let words: Vec<&str> = s.split(|c: char| c == '_' || c == ' ').collect();
21
22 if words.len() == 1 && words[0].chars().next().unwrap_or_default().is_uppercase() {
24 let mut chars = words[0].chars();
25 let first_char = chars.next().unwrap_or_default().to_lowercase();
26 return format!(
27 "{}{}",
28 first_char.collect::<String>(),
29 chars.collect::<String>()
30 );
31 }
32
33 let first_word = words[0].to_lowercase();
35
36 let rest: String = words[1..]
38 .iter()
39 .map(|word| {
40 let mut chars = word.chars();
41 let first_char = chars.next().unwrap_or_default().to_uppercase();
42 format!(
43 "{}{}",
44 first_char.collect::<String>(),
45 chars.collect::<String>()
46 )
47 })
48 .collect();
49
50 format!("{}{}", first_word, rest)
51}
52
53pub fn to_pascal_case(s: &str) -> String {
55 s.split(|c: char| c == '_' || c == ' ')
56 .map(|word| capitalize_first(word))
57 .collect()
58}
59
60fn capitalize_first(s: &str) -> String {
62 let mut chars = s.chars();
63 match chars.next() {
64 None => String::new(),
65 Some(f) => f.to_uppercase().collect::<String>() + chars.as_str(),
66 }
67}
68
69pub fn to_screaming_snake_case(s: &str) -> String {
70 to_snake_case(s).to_uppercase()
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[cfg(test)]
78 mod tests {
79 use super::*;
80
81 #[test]
82 fn test_to_snake_case() {
83 let cases = vec![
84 ("HelloWorld", "hello_world"),
85 ("snakeCase", "snake_case"),
86 ("PascalCase", "pascal_case"),
87 ("With Spaces", "with_spaces"),
88 ("already_snakecase", "already_snakecase"),
89 ];
90
91 for (input, expected) in cases {
92 assert_eq!(to_snake_case(input), expected);
93 }
94 }
95
96 #[test]
97 fn test_to_camel_case() {
98 let cases = vec![
99 ("Hello World", "helloWorld"),
100 ("snake_case", "snakeCase"),
101 ("PascalCase", "pascalCase"),
102 ("with spaces", "withSpaces"),
103 ("already_Camelcase", "alreadyCamelcase"),
104 ];
105
106 for (input, expected) in cases {
107 assert_eq!(to_camel_case(input), expected);
108 }
109 }
110
111 #[test]
112 fn test_to_screaming_snake_case() {
113 let cases = vec![
114 ("HelloWorld", "HELLO_WORLD"),
115 ("snakeCase", "SNAKE_CASE"),
116 ("PascalCase", "PASCAL_CASE"),
117 ("With Spaces", "WITH_SPACES"),
118 ];
119
120 for (input, expected) in cases {
121 assert_eq!(to_screaming_snake_case(input), expected);
122 }
123 }
124
125 #[test]
126 fn test_to_pascal_case() {
127 let cases = vec![
128 ("hello world", "HelloWorld"),
129 ("snake_case", "SnakeCase"),
130 ("camelCase", "CamelCase"),
131 ("with spaces", "WithSpaces"),
132 ("AlreadyPascalCase", "AlreadyPascalCase"),
133 ];
134
135 for (input, expected) in cases {
136 assert_eq!(to_pascal_case(input), expected);
137 }
138 }
139 }
140}