Skip to main content

ferriorm_core/
utils.rs

1//! String case-conversion utilities used across the ferriorm workspace.
2//!
3//! Provides [`to_snake_case`], [`to_pascal_case`], and [`to_camel_case`] for
4//! converting between naming conventions (e.g., model names to table names,
5//! column names to Rust field names).
6
7/// Convert `PascalCase` or `camelCase` to `snake_case`.
8///
9/// # Panics
10///
11/// Panics if a character's lowercase conversion produces no characters,
12/// which cannot happen for valid Unicode.
13#[must_use]
14pub fn to_snake_case(s: &str) -> String {
15    let mut result = String::new();
16    for (i, c) in s.chars().enumerate() {
17        if c.is_uppercase() && i > 0 {
18            result.push('_');
19        }
20        result.push(c.to_lowercase().next().unwrap());
21    }
22    result
23}
24
25/// Convert `snake_case` to `PascalCase`.
26///
27/// # Panics
28///
29/// Panics if a character's uppercase conversion produces no characters,
30/// which cannot happen for valid Unicode.
31#[must_use]
32pub fn to_pascal_case(s: &str) -> String {
33    let mut result = String::new();
34    let mut capitalize_next = true;
35    for c in s.chars() {
36        if c == '_' {
37            capitalize_next = true;
38        } else if capitalize_next {
39            result.push(c.to_uppercase().next().unwrap());
40            capitalize_next = false;
41        } else {
42            result.push(c);
43        }
44    }
45    result
46}
47
48/// Convert `snake_case` to `camelCase`.
49#[must_use]
50pub fn to_camel_case(s: &str) -> String {
51    let pascal = to_pascal_case(s);
52    let mut chars = pascal.chars();
53    match chars.next() {
54        Some(c) => c.to_lowercase().collect::<String>() + chars.as_str(),
55        None => String::new(),
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62
63    #[test]
64    fn test_to_snake_case() {
65        assert_eq!(to_snake_case("User"), "user");
66        assert_eq!(to_snake_case("PostTag"), "post_tag");
67        assert_eq!(to_snake_case("createdAt"), "created_at");
68        assert_eq!(to_snake_case("HTMLParser"), "h_t_m_l_parser");
69    }
70
71    #[test]
72    fn test_to_pascal_case() {
73        assert_eq!(to_pascal_case("user"), "User");
74        assert_eq!(to_pascal_case("post_tag"), "PostTag");
75        assert_eq!(to_pascal_case("created_at"), "CreatedAt");
76    }
77
78    #[test]
79    fn test_to_camel_case() {
80        assert_eq!(to_camel_case("user_name"), "userName");
81        assert_eq!(to_camel_case("created_at"), "createdAt");
82        assert_eq!(to_camel_case("id"), "id");
83    }
84}