cases2 0.1.0

A simple utility library for converting Rust nameconventions.
Documentation
pub fn to_snake_case(s: &str) -> String {
    let mut snake = String::new();
    let chars: Vec<char> = s.chars().collect();
    for (i, c) in chars.iter().enumerate() {
        if c.is_whitespace() {
            snake.push('_');
            continue;
        }

        if c.is_uppercase() && i != 0 && chars[i - 1] != ' ' {
            snake.push('_');
        }
        snake.extend(c.to_lowercase());
    }
    snake
}

/// Converts a string to camelCase
pub fn to_camel_case(s: &str) -> String {
    let words: Vec<&str> = s.split(|c: char| c == '_' || c == ' ').collect();

    // If only one word and it starts with uppercase, treat it specially.
    if words.len() == 1 && words[0].chars().next().unwrap_or_default().is_uppercase() {
        let mut chars = words[0].chars();
        let first_char = chars.next().unwrap_or_default().to_lowercase();
        return format!(
            "{}{}",
            first_char.collect::<String>(),
            chars.collect::<String>()
        );
    }

    // First word is always in lowercase
    let first_word = words[0].to_lowercase();

    // Remaining words have their first character capitalized
    let rest: String = words[1..]
        .iter()
        .map(|word| {
            let mut chars = word.chars();
            let first_char = chars.next().unwrap_or_default().to_uppercase();
            format!(
                "{}{}",
                first_char.collect::<String>(),
                chars.collect::<String>()
            )
        })
        .collect();

    format!("{}{}", first_word, rest)
}

/// Converts a string to PascalCase.
pub fn to_pascal_case(s: &str) -> String {
    s.split(|c: char| c == '_' || c == ' ')
        .map(|word| capitalize_first(word))
        .collect()
}

/// Helper function to capitalize the first letter of a string.
fn capitalize_first(s: &str) -> String {
    let mut chars = s.chars();
    match chars.next() {
        None => String::new(),
        Some(f) => f.to_uppercase().collect::<String>() + chars.as_str(),
    }
}

pub fn to_screaming_snake_case(s: &str) -> String {
    to_snake_case(s).to_uppercase()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[cfg(test)]
    mod tests {
        use super::*;

        #[test]
        fn test_to_snake_case() {
            let cases = vec![
                ("HelloWorld", "hello_world"),
                ("snakeCase", "snake_case"),
                ("PascalCase", "pascal_case"),
                ("With Spaces", "with_spaces"),
                ("already_snakecase", "already_snakecase"),
            ];

            for (input, expected) in cases {
                assert_eq!(to_snake_case(input), expected);
            }
        }

        #[test]
        fn test_to_camel_case() {
            let cases = vec![
                ("Hello World", "helloWorld"),
                ("snake_case", "snakeCase"),
                ("PascalCase", "pascalCase"),
                ("with spaces", "withSpaces"),
                ("already_Camelcase", "alreadyCamelcase"),
            ];

            for (input, expected) in cases {
                assert_eq!(to_camel_case(input), expected);
            }
        }

        #[test]
        fn test_to_screaming_snake_case() {
            let cases = vec![
                ("HelloWorld", "HELLO_WORLD"),
                ("snakeCase", "SNAKE_CASE"),
                ("PascalCase", "PASCAL_CASE"),
                ("With Spaces", "WITH_SPACES"),
            ];

            for (input, expected) in cases {
                assert_eq!(to_screaming_snake_case(input), expected);
            }
        }

        #[test]
        fn test_to_pascal_case() {
            let cases = vec![
                ("hello world", "HelloWorld"),
                ("snake_case", "SnakeCase"),
                ("camelCase", "CamelCase"),
                ("with spaces", "WithSpaces"),
                ("AlreadyPascalCase", "AlreadyPascalCase"),
            ];

            for (input, expected) in cases {
                assert_eq!(to_pascal_case(input), expected);
            }
        }
    }
}