use crate::types::MethodKind;
pub(crate) fn to_snake(camel: &str, kind: MethodKind) -> String {
debug_assert!(!camel.is_empty(), "Called `to_snake` with empty string");
let preamble = match kind {
MethodKind::Set => "set_",
MethodKind::Remove => "remove_",
_ => "",
};
let mut snake = String::with_capacity(preamble.len() + camel.len());
snake.push_str(preamble);
let mut since_last_underscore = 0;
let mut chars = camel.chars();
for c in chars.next().unwrap().to_lowercase() {
since_last_underscore += 1;
snake.push(c);
}
for (previous, next) in camel.chars().zip(camel.chars().skip(2)) {
let current = chars.next().unwrap();
if !current.is_uppercase() {
since_last_underscore += 1;
snake.push(current);
continue;
}
if previous.is_lowercase() || next.is_lowercase() && since_last_underscore > 1 {
since_last_underscore = 0;
if previous != '_' {
snake.push('_');
}
}
for c in current.to_lowercase() {
since_last_underscore += 1;
snake.push(c);
}
}
if let Some(last) = chars.next() {
snake.extend(last.to_lowercase());
}
snake
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn to_snake_works() {
assert_eq!(
to_snake("Windows", MethodKind::Normal),
"windows".to_owned()
);
assert_eq!(
to_snake("ApplicationModel", MethodKind::Normal),
"application_model".to_owned()
);
assert_eq!(to_snake("foo", MethodKind::Normal), "foo".to_owned());
assert_eq!(
to_snake("UIProgramming", MethodKind::Normal),
"ui_programming".to_owned()
);
assert_eq!(
to_snake("UIProgramming", MethodKind::Set),
"set_ui_programming".to_owned()
);
assert_eq!(
to_snake("CreateUInt8Array", MethodKind::Normal),
"create_uint8_array".to_owned()
);
assert_eq!(
to_snake("Socks", MethodKind::Remove),
"remove_socks".to_owned()
);
assert_eq!(
to_snake("appointmentId", MethodKind::Normal),
"appointment_id".to_owned()
);
assert_eq!(to_snake("a", MethodKind::Normal), "a".to_owned());
assert_eq!(
to_snake("CreateField_Default", MethodKind::Normal),
"create_field_default".to_owned()
);
}
}