use heck::{ToPascalCase, ToShoutySnakeCase};
pub(super) fn apply_initialisms(name: &str, list: &[&str]) -> String {
if name.is_empty() {
return name.to_string();
}
let mut words: Vec<&str> = Vec::new();
let mut word_start = 0;
let bytes = name.as_bytes();
for i in 1..bytes.len() {
if bytes[i].is_ascii_uppercase() {
words.push(&name[word_start..i]);
word_start = i;
}
}
words.push(&name[word_start..]);
let mut result = String::with_capacity(name.len());
let mut i = 0;
while i < words.len() {
let mut matched = false;
for span in (1..=(words.len() - i)).rev() {
let candidate: String = words[i..i + span].concat();
let candidate_upper = candidate.to_ascii_uppercase();
if let Some(&canonical) = list.iter().find(|&&s| s.to_ascii_uppercase() == candidate_upper) {
result.push_str(canonical);
i += span;
matched = true;
break;
}
}
if !matched {
result.push_str(words[i]);
i += 1;
}
}
result
}
pub(super) fn normalize_acronym_to_pascalcase(name: &str) -> String {
if name.is_empty() {
return name.to_string();
}
if name.len() >= 3 && name.chars().all(|c| c.is_ascii_uppercase()) {
let mut result = String::with_capacity(name.len());
result.push(name.chars().next().unwrap().to_ascii_uppercase());
result.extend(name.chars().skip(1).map(|c| c.to_ascii_lowercase()));
return result;
}
name.to_string()
}
pub fn to_class_name(name: &str) -> String {
name.to_pascal_case()
}
pub fn to_constant_name(name: &str) -> String {
name.to_shouty_snake_case()
}
pub fn pascal_to_snake(name: &str) -> String {
if name.is_empty() {
return String::new();
}
let chars: Vec<char> = name.chars().collect();
let n = chars.len();
let mut out = String::with_capacity(n + 4);
let mut i = 0;
while i < n {
let ch = chars[i];
if ch.is_ascii_uppercase() {
let run_start = i;
while i < n && chars[i].is_ascii_uppercase() {
i += 1;
}
let run_end = i;
let run_len = run_end - run_start;
if run_len == 1 {
if !out.is_empty() {
out.push('_');
}
out.extend(chars[run_start].to_lowercase());
} else {
let split = if i < n && chars[i].is_ascii_lowercase() {
run_len - 1
} else {
run_len
};
if !out.is_empty() {
out.push('_');
}
for &c in chars.iter().skip(run_start).take(split) {
out.extend(c.to_lowercase());
}
if split < run_len {
out.push('_');
out.extend(chars[run_start + split].to_lowercase());
}
}
} else {
out.push(ch);
i += 1;
}
}
out
}
pub fn pascal_to_screaming_snake(name: &str) -> String {
pascal_to_snake(name).to_ascii_uppercase()
}
pub fn underscore_camel_case(name: &str) -> String {
let mut result = String::with_capacity(name.len());
let mut capitalize_next = false;
for ch in name.chars() {
if ch == '_' {
capitalize_next = true;
} else if capitalize_next {
result.extend(ch.to_uppercase());
capitalize_next = false;
} else {
result.push(ch);
}
}
result
}