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