1use rand::Rng;
4
5pub fn slugify(s: &str) -> String {
7 s.to_lowercase()
8 .chars()
9 .map(|c| {
10 if c.is_alphanumeric() {
11 c
12 } else if c.is_whitespace() || c == '-' || c == '_' {
13 '-'
14 } else {
15 '\0'
16 }
17 })
18 .filter(|c| *c != '\0')
19 .collect::<String>()
20 .split('-')
21 .filter(|s| !s.is_empty())
22 .collect::<Vec<_>>()
23 .join("-")
24}
25
26pub fn truncate(s: &str, max_len: usize) -> String {
28 let char_count = s.chars().count();
29 if char_count <= max_len {
30 s.to_string()
31 } else if max_len <= 3 {
32 s.chars().take(max_len).collect()
33 } else {
34 format!("{}...", s.chars().take(max_len - 3).collect::<String>())
35 }
36}
37
38pub fn capitalize(s: &str) -> String {
40 let mut chars = s.chars();
41 match chars.next() {
42 None => String::new(),
43 Some(first) => first.to_uppercase().chain(chars).collect(),
44 }
45}
46
47pub fn random_string(length: usize) -> String {
49 const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
50 let mut rng = rand::rng();
51
52 (0..length)
53 .map(|_| {
54 let idx = rng.random_range(0..CHARSET.len());
55 CHARSET[idx] as char
56 })
57 .collect()
58}
59
60pub fn camel_case(s: &str) -> String {
62 let words: Vec<&str> = s.split(|c: char| c == '_' || c == '-' || c.is_whitespace())
63 .filter(|s| !s.is_empty())
64 .collect();
65
66 if words.is_empty() {
67 return String::new();
68 }
69
70 let mut result = words[0].to_lowercase();
71 for word in &words[1..] {
72 result.push_str(&capitalize(&word.to_lowercase()));
73 }
74 result
75}
76
77pub fn snake_case(s: &str) -> String {
79 let mut result = String::new();
80 for (i, c) in s.chars().enumerate() {
81 if c.is_uppercase() {
82 if i > 0 {
83 result.push('_');
84 }
85 result.push(c.to_lowercase().next().unwrap());
86 } else if c == '-' || c.is_whitespace() {
87 result.push('_');
88 } else {
89 result.push(c);
90 }
91 }
92 result
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn test_slugify() {
101 assert_eq!(slugify("Hello World"), "hello-world");
102 assert_eq!(slugify("This is a Test!"), "this-is-a-test");
103 assert_eq!(slugify(" Multiple Spaces "), "multiple-spaces");
104 }
105
106 #[test]
107 fn test_truncate() {
108 assert_eq!(truncate("Hello World", 5), "He...");
109 assert_eq!(truncate("Hi", 5), "Hi");
110 assert_eq!(truncate("Hello", 5), "Hello");
111 assert_eq!(truncate("éééé", 3), "ééé");
112 }
113
114 #[test]
115 fn test_capitalize() {
116 assert_eq!(capitalize("hello"), "Hello");
117 assert_eq!(capitalize("HELLO"), "HELLO");
118 assert_eq!(capitalize(""), "");
119 }
120
121 #[test]
122 fn test_camel_case() {
123 assert_eq!(camel_case("hello_world"), "helloWorld");
124 assert_eq!(camel_case("user-name"), "userName");
125 }
126
127 #[test]
128 fn test_snake_case() {
129 assert_eq!(snake_case("helloWorld"), "hello_world");
130 assert_eq!(snake_case("UserName"), "user_name");
131 }
132}