scsys_util/str/
casing.rs

1/*
2    Appellation: casing <module>
3    Contrib: FL03 <jo3mccain@icloud.com>
4*/
5#[cfg(feature = "alloc")]
6#[doc(inline)]
7pub use self::utils::*;
8
9#[derive(
10    Clone,
11    Copy,
12    Debug,
13    Default,
14    Eq,
15    Hash,
16    Ord,
17    PartialEq,
18    PartialOrd,
19    strum::AsRefStr,
20    strum::Display,
21    strum::EnumCount,
22    strum::EnumIs,
23    strum::EnumIter,
24    strum::EnumString,
25    strum::VariantArray,
26    strum::VariantNames,
27)]
28#[cfg_attr(
29    feature = "serde",
30    derive(serde::Deserialize, serde::Serialize,),
31    serde(rename_all = "snake_case")
32)]
33#[strum(serialize_all = "snake_case")]
34pub enum CaseType {
35    CamelCase,
36    KebabCase,
37    PascalCase,
38    #[default]
39    SnakeCase,
40}
41
42#[cfg(feature = "alloc")]
43impl CaseType {
44    /// Converts a string to the specified case.
45    pub fn convert(&self, s: &str) -> alloc::string::String {
46        match self {
47            Self::CamelCase => utils::to_camelcase(s),
48            Self::KebabCase => utils::to_kebabcase(s),
49            Self::PascalCase => utils::to_pascalcase(s),
50            Self::SnakeCase => utils::to_snakecase(s),
51        }
52    }
53}
54
55#[cfg(feature = "alloc")]
56mod utils {
57    use alloc::string::String;
58
59    /// Converts a string to snake_case.
60    pub fn to_snakecase(s: &str) -> String {
61        s.chars()
62            .fold(String::new(), |mut acc, c| {
63                if c.is_uppercase() {
64                    if !acc.is_empty() {
65                        acc.push('_');
66                    }
67                    acc.push(c.to_lowercase().next().unwrap());
68                } else {
69                    acc.push(c);
70                }
71                acc
72            })
73            .to_lowercase()
74    }
75
76    /// Converts a string to camelCase.
77    pub fn to_camelcase(s: &str) -> String {
78        let mut chars = s.chars();
79        let first = chars.next().unwrap();
80        let rest = chars.collect::<String>();
81        format!("{}{}", first.to_lowercase(), rest)
82    }
83
84    /// Converts a string to PascalCase.
85    pub fn to_pascalcase(s: &str) -> String {
86        let mut chars = s.chars();
87        let first = chars.next().unwrap();
88        let rest = chars.collect::<String>();
89        format!("{}{}", first.to_uppercase(), rest)
90    }
91
92    /// Converts a string to kebab-case.
93    pub fn to_kebabcase(s: &str) -> String {
94        s.chars()
95            .fold(String::new(), |mut acc, c| {
96                if c.is_uppercase() {
97                    if !acc.is_empty() {
98                        acc.push('-');
99                    }
100                    acc.push(c.to_lowercase().next().unwrap());
101                } else {
102                    acc.push(c);
103                }
104                acc
105            })
106            .to_lowercase()
107    }
108
109    /// Converts a string to SCREAMING_SNAKE_CASE.
110    pub fn to_screaming_snakecase(s: &str) -> String {
111        s.chars().fold(String::new(), |mut acc, c| {
112            if c.is_uppercase() {
113                if !acc.is_empty() {
114                    acc.push('_');
115                }
116                acc.push(c);
117            } else {
118                acc.push(c.to_uppercase().next().unwrap());
119            }
120            acc
121        })
122    }
123}