1 use heck::{CamelCase, KebabCase, MixedCase, ShoutySnakeCase, SnakeCase, TitleCase};
2 
3 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
4 pub enum CaseStyle {
5     CamelCase,
6     KebabCase,
7     MixedCase,
8     ShoutySnakeCase,
9     SnakeCase,
10     TitleCase,
11     UpperCase,
12     LowerCase,
13     ScreamingKebabCase,
14     PascalCase,
15 }
16 
17 impl<'s> From<&'s str> for CaseStyle {
from(text: &'s str) -> CaseStyle18     fn from(text: &'s str) -> CaseStyle {
19         match text {
20             "camel_case" | "PascalCase" => CaseStyle::PascalCase,
21             "camelCase" => CaseStyle::CamelCase,
22             "snake_case" | "snek_case" => CaseStyle::SnakeCase,
23             "kebab_case" | "kebab-case" => CaseStyle::KebabCase,
24             "SCREAMING-KEBAB-CASE" => CaseStyle::ScreamingKebabCase,
25             "shouty_snake_case" | "shouty_snek_case" | "SCREAMING_SNAKE_CASE" => {
26                 CaseStyle::ShoutySnakeCase
27             }
28             "title_case" => CaseStyle::TitleCase,
29             "mixed_case" => CaseStyle::MixedCase,
30             "lowercase" => CaseStyle::LowerCase,
31             "UPPERCASE" => CaseStyle::UpperCase,
32             _ => panic!(
33                 "Unexpected case style for serialize_all: `{}`. Valid values are: `{:?}`",
34                 text,
35                 [
36                     "camelCase",
37                     "PascalCase",
38                     "kebab-case",
39                     "snake_case",
40                     "SCREAMING_SNAKE_CASE",
41                     "SCREAMING-KEBAB-CASE",
42                     "lowercase",
43                     "UPPERCASE",
44                     "title_case",
45                     "mixed_case",
46                 ]
47             ),
48         }
49     }
50 }
51 
52 pub trait CaseStyleHelpers {
convert_case(&self, case_style: Option<CaseStyle>) -> String53     fn convert_case(&self, case_style: Option<CaseStyle>) -> String;
54 }
55 
56 impl CaseStyleHelpers for syn::Ident {
convert_case(&self, case_style: Option<CaseStyle>) -> String57     fn convert_case(&self, case_style: Option<CaseStyle>) -> String {
58         let ident_string = self.to_string();
59         if let Some(case_style) = case_style {
60             match case_style {
61                 CaseStyle::PascalCase => ident_string.to_camel_case(),
62                 CaseStyle::KebabCase => ident_string.to_kebab_case(),
63                 CaseStyle::MixedCase => ident_string.to_mixed_case(),
64                 CaseStyle::ShoutySnakeCase => ident_string.to_shouty_snake_case(),
65                 CaseStyle::SnakeCase => ident_string.to_snake_case(),
66                 CaseStyle::TitleCase => ident_string.to_title_case(),
67                 CaseStyle::UpperCase => ident_string.to_uppercase(),
68                 CaseStyle::LowerCase => ident_string.to_lowercase(),
69                 CaseStyle::ScreamingKebabCase => ident_string.to_kebab_case().to_uppercase(),
70                 CaseStyle::CamelCase => {
71                     let camel_case = ident_string.to_camel_case();
72                     let mut pascal = String::with_capacity(camel_case.len());
73                     let mut it = camel_case.chars();
74                     if let Some(ch) = it.next() {
75                         pascal.extend(ch.to_lowercase());
76                     }
77                     pascal.extend(it);
78                     pascal
79                 }
80             }
81         } else {
82             ident_string
83         }
84     }
85 }
86 
87 #[test]
test_convert_case()88 fn test_convert_case() {
89     let id = syn::Ident::new("test_me", proc_macro2::Span::call_site());
90     assert_eq!("testMe", id.convert_case(Some(CaseStyle::CamelCase)));
91     assert_eq!("TestMe", id.convert_case(Some(CaseStyle::PascalCase)));
92 }
93