1pub fn split_words(s: &str) -> String {
5 let mut out = String::with_capacity(s.len() + 4);
6 let chars: Vec<char> = s.chars().collect();
7 for (i, &c) in chars.iter().enumerate() {
8 if c.is_uppercase() && i > 0 && chars[i - 1].is_lowercase() {
9 out.push('_');
10 }
11 out.push(c);
12 }
13 out
14}
15
16pub fn pascal_case(s: &str) -> String {
18 split_words(s)
19 .split('_')
20 .filter(|w| !w.is_empty())
21 .map(|w| {
22 let mut c = w.chars();
23 match c.next() {
24 None => String::new(),
25 Some(f) => f.to_uppercase().collect::<String>() + c.as_str(),
26 }
27 })
28 .collect()
29}
30
31pub fn camel_case(s: &str) -> String {
33 let p = pascal_case(s);
34 let mut c = p.chars();
35 match c.next() {
36 None => String::new(),
37 Some(f) => f.to_lowercase().collect::<String>() + c.as_str(),
38 }
39}
40
41pub fn snake_case(name: &str) -> String {
44 let mut out = String::with_capacity(name.len() + 4);
45 let chars: Vec<char> = name.chars().collect();
46 for (i, &c) in chars.iter().enumerate() {
47 if c.is_uppercase() && i > 0 && chars[i - 1].is_lowercase() {
48 out.push('_');
49 }
50 out.push(c.to_ascii_lowercase());
51 }
52 out
53}
54
55pub fn escape_string(s: &str) -> String {
58 let serialized = serde_json::to_string(s).unwrap_or_else(|_| format!("\"{}\"", s));
59 serialized[1..serialized.len() - 1].to_string()
61}
62
63#[cfg(test)]
66mod tests {
67 use super::*;
68
69 #[test]
70 fn pascal_case_snake() {
71 assert_eq!(pascal_case("user_status"), "UserStatus");
72 }
73
74 #[test]
75 fn pascal_case_single() {
76 assert_eq!(pascal_case("users"), "Users");
77 }
78
79 #[test]
80 fn camel_case_snake() {
81 assert_eq!(camel_case("get_user"), "getUser");
82 }
83
84 #[test]
85 fn split_words_pascal() {
86 assert_eq!(split_words("GetUser"), "Get_User");
87 }
88
89 #[test]
90 fn escape_string_quotes() {
91 assert_eq!(escape_string("he said \"hi\""), "he said \\\"hi\\\"");
92 }
93}