cases2/
lib.rs

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
18/// Converts a string to camelCase
19pub fn to_camel_case(s: &str) -> String {
20    let words: Vec<&str> = s.split(|c: char| c == '_' || c == ' ').collect();
21
22    // If only one word and it starts with uppercase, treat it specially.
23    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    // First word is always in lowercase
34    let first_word = words[0].to_lowercase();
35
36    // Remaining words have their first character capitalized
37    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
53/// Converts a string to PascalCase.
54pub fn to_pascal_case(s: &str) -> String {
55    s.split(|c: char| c == '_' || c == ' ')
56        .map(|word| capitalize_first(word))
57        .collect()
58}
59
60/// Helper function to capitalize the first letter of a string.
61fn 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}