cynic_codegen/idents/
old_ident.rs1#[derive(Debug, Clone, Copy)]
2pub enum RenameAll {
5 None,
6 Lowercase,
8 Uppercase,
10 PascalCase,
12 CamelCase,
14 SnakeCase,
16 ScreamingSnakeCase,
18}
19
20impl RenameAll {
21 pub(super) fn apply(&self, string: impl AsRef<str>) -> String {
22 match self {
23 RenameAll::Lowercase => string.as_ref().to_lowercase(),
24 RenameAll::Uppercase => string.as_ref().to_uppercase(),
25 RenameAll::PascalCase => to_pascal_case(string.as_ref()),
26 RenameAll::CamelCase => to_camel_case(string.as_ref()),
27 RenameAll::SnakeCase => to_snake_case(string.as_ref()),
28 RenameAll::ScreamingSnakeCase => to_snake_case(string.as_ref()).to_uppercase(),
29 RenameAll::None => string.as_ref().to_string(),
30 }
31 }
32}
33
34impl darling::FromMeta for RenameAll {
35 fn from_string(value: &str) -> Result<RenameAll, darling::Error> {
36 match value.to_lowercase().as_ref() {
37 "none" => Ok(RenameAll::None),
38 "lowercase" => Ok(RenameAll::Lowercase),
39 "uppercase" => Ok(RenameAll::Uppercase),
40 "pascalcase" => Ok(RenameAll::PascalCase),
41 "camelcase" => Ok(RenameAll::CamelCase),
42 "snake_case" => Ok(RenameAll::SnakeCase),
43 "screaming_snake_case" => Ok(RenameAll::ScreamingSnakeCase),
44 _ => {
45 Err(darling::Error::unknown_value(value))
47 }
48 }
49 }
50}
51
52pub fn to_snake_case(s: &str) -> String {
53 let mut buf = String::with_capacity(s.len());
54 let mut prev_is_upper = true;
56 for c in s.chars() {
57 if c.is_uppercase() && !prev_is_upper {
58 buf.push('_');
59 buf.extend(c.to_lowercase());
60 prev_is_upper = true;
61 } else if c.is_uppercase() {
62 buf.extend(c.to_lowercase());
63 } else {
64 prev_is_upper = false;
65 buf.push(c);
66 }
67 }
68 buf
69}
70
71pub fn to_pascal_case(s: &str) -> String {
73 let mut buf = String::with_capacity(s.len());
74 let mut first_char = true;
75 let mut prev_is_upper = false;
76 let mut prev_is_underscore = false;
77 let mut chars = s.chars().peekable();
78 loop {
79 let c = chars.next();
80 if c.is_none() {
81 break;
82 }
83 let c = c.unwrap();
84 if first_char {
85 if c == '_' {
86 buf.push('_');
88 while let Some('_') = chars.peek() {
89 buf.push(chars.next().unwrap());
90 }
91 } else if c.is_uppercase() {
92 prev_is_upper = true;
93 buf.push(c);
94 } else {
95 buf.extend(c.to_uppercase());
96 }
97 first_char = false;
98 continue;
99 }
100
101 if c.is_uppercase() {
102 if prev_is_upper {
103 buf.extend(c.to_lowercase());
104 } else {
105 buf.push(c);
106 }
107 prev_is_upper = true;
108 } else if c == '_' {
109 prev_is_underscore = true;
110 prev_is_upper = false;
111 } else {
112 if prev_is_upper {
113 buf.extend(c.to_lowercase())
114 } else if prev_is_underscore {
115 buf.extend(c.to_uppercase());
116 } else {
117 buf.push(c);
118 }
119 prev_is_upper = false;
120 prev_is_underscore = false;
121 }
122 }
123
124 buf
125}
126
127pub(super) fn to_camel_case(s: &str) -> String {
128 let s = to_pascal_case(s);
129
130 let mut buf = String::with_capacity(s.len());
131 let mut chars = s.chars();
132
133 if let Some(first_char) = chars.next() {
134 buf.extend(first_char.to_lowercase());
135 }
136
137 buf.extend(chars);
138
139 buf
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 #[test]
147 fn test_underscore() {
148 assert_eq!(to_snake_case("_hello"), "_hello");
149 assert_eq!(to_snake_case("_"), "_");
150 }
151
152 #[test]
153 fn test_to_snake_case() {
154 assert_eq!(to_snake_case("aString"), "a_string");
155 assert_eq!(to_snake_case("MyString"), "my_string");
156 assert_eq!(to_snake_case("my_string"), "my_string");
157 assert_eq!(to_snake_case("_another_one"), "_another_one");
158 assert_eq!(to_snake_case("RepeatedUPPERCASE"), "repeated_uppercase");
159 assert_eq!(to_snake_case("UUID"), "uuid");
160 }
161
162 #[test]
163 fn test_to_camel_case() {
164 assert_eq!(to_camel_case("aString"), "aString");
165 assert_eq!(to_camel_case("MyString"), "myString");
166 assert_eq!(to_camel_case("my_string"), "myString");
167 assert_eq!(to_camel_case("_another_one"), "_anotherOne");
168 assert_eq!(to_camel_case("RepeatedUPPERCASE"), "repeatedUppercase");
169 assert_eq!(to_camel_case("UUID"), "uuid");
170 assert_eq!(to_camel_case("__typename"), "__typename");
171 }
172
173 #[test]
174 fn test_to_pascal_case() {
175 assert_eq!(to_pascal_case("aString"), "AString");
176 assert_eq!(to_pascal_case("MyString"), "MyString");
177 assert_eq!(to_pascal_case("my_string"), "MyString");
178 assert_eq!(to_pascal_case("_another_one"), "_anotherOne");
179 assert_eq!(to_pascal_case("RepeatedUPPERCASE"), "RepeatedUppercase");
180 assert_eq!(to_pascal_case("UUID"), "Uuid");
181 assert_eq!(to_pascal_case("CREATED_AT"), "CreatedAt");
182 assert_eq!(to_pascal_case("__typename"), "__typename");
183 }
184
185 #[test]
186 fn casings_are_not_lossy_where_possible() {
187 for s in ["snake_case_thing", "snake"] {
188 assert_eq!(to_snake_case(&to_pascal_case(s)), s);
189 }
190
191 for s in ["PascalCase", "Pascal"] {
192 assert_eq!(to_pascal_case(&to_snake_case(s)), s);
193 }
194
195 for s in ["camelCase", "camel"] {
196 assert_eq!(to_camel_case(&to_snake_case(s)), s);
197 }
198 }
199}