1#[cfg(test)]
7mod tests {
8 use super::*;
9 #[test]
10 fn case_recogniser() {
11 use Case::*;
12 assert_eq!(Case::compute("snakecase"), SnakeCase);
13 assert_eq!(Case::compute("snake_case"), SnakeCase);
14 assert_eq!(Case::compute("PascalCase"), PascalCase);
15 assert_eq!(Case::compute("camelCase"), CamelCase);
16 assert_eq!(Case::compute("Pascal_Snake_Case"), PascalSnakeCase);
17 assert_eq!(Case::compute("UPPERCASE"), UpperCase);
18 assert_eq!(Case::compute("SCREAMING_SNAKE_CASE"), ScreamingSnakeCase);
19 assert_eq!(Case::compute(""), Other);
20 assert_eq!(Case::compute("__"), Other);
21 assert_eq!(Case::compute("fake snake case"), Other);
22 }
23}
24
25#[derive(Debug, PartialEq, Eq)]
29#[allow(clippy::enum_variant_names)]
30pub enum Case {
31 SnakeCase,
33 PascalCase,
35 CamelCase,
37 PascalSnakeCase,
39 UpperCase,
41 ScreamingSnakeCase,
43 Other,
45}
46
47impl Case {
48 pub fn compute(string: &str) -> Self {
49 if string.is_empty() {
50 return Self::Other;
51 }
52
53 let mut contains_underscore = false;
54 let mut first_is_capital = false;
55 let mut contains_small = false;
56 let mut contains_capital = false;
57
58 let mut contains_non_alphanumeric = false;
59
60 let mut first_alpha = true;
61
62 for c in string.chars() {
63 if c == '_' {
64 contains_underscore = true;
65 } else if c.is_ascii_uppercase() {
66 contains_capital = true;
67 if first_alpha {
68 first_is_capital = true;
69 }
70 first_alpha = false;
71 } else if c.is_ascii_lowercase() {
72 contains_small = true;
73 first_alpha = false;
74 } else {
75 contains_non_alphanumeric = true;
76 }
77 }
78
79 if first_alpha || contains_non_alphanumeric {
80 Self::Other
81 } else if !contains_capital {
82 Self::SnakeCase
83 } else if !first_is_capital {
84 Self::CamelCase
85 } else if contains_small {
86 if contains_underscore {
87 Self::PascalSnakeCase
88 } else {
89 Self::PascalCase
90 }
91 } else if contains_underscore {
92 Self::ScreamingSnakeCase
93 } else {
94 Self::UpperCase
95 }
96 }
97}
98
99pub trait CaseProcess {
100 fn case(&self) -> Case;
101}
102
103impl CaseProcess for &str {
104 fn case(&self) -> Case {
105 Case::compute(self)
106 }
107}
108
109impl CaseProcess for String {
110 fn case(&self) -> Case {
111 Case::compute(self.as_str())
112 }
113}