1use rand::Rng;
9
10const ADJECTIVES: &[&str] = &[
12 "brave", "calm", "clever", "cosmic", "crisp", "curious", "eager", "gentle", "glowing", "happy",
13 "hidden", "jolly", "kind", "lucky", "mighty", "misty", "neon", "nimble", "playful", "proud",
14 "quick", "quiet", "shiny", "silent", "stellar", "sunny", "swift", "tidy", "witty", "bright",
15];
16
17const NOUNS: &[&str] = &[
19 "cabin", "cactus", "canyon", "circuit", "comet", "eagle", "engine", "falcon", "forest",
20 "garden", "harbor", "island", "knight", "lagoon", "meadow", "moon", "mountain", "nebula",
21 "orchid", "otter", "panda", "pixel", "planet", "river", "rocket", "sailor", "squid", "star",
22 "tiger", "wizard", "wolf", "stream",
23];
24
25pub fn create() -> String {
37 let mut rng = rand::rng();
38 let adj_idx = rng.random_range(0..ADJECTIVES.len());
39 let noun_idx = rng.random_range(0..NOUNS.len());
40
41 format!("{}-{}", ADJECTIVES[adj_idx], NOUNS[noun_idx])
42}
43
44pub fn create_timestamped() -> String {
57 let timestamp = std::time::SystemTime::now()
58 .duration_since(std::time::UNIX_EPOCH)
59 .map(|d| d.as_millis())
60 .unwrap_or(0);
61
62 format!("{}-{}", timestamp, create())
63}
64
65pub fn create_with_prefix(prefix: &str) -> String {
76 format!("{}-{}", prefix, create())
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82
83 #[test]
84 fn test_create_slug() {
85 let slug = create();
86 assert!(slug.contains('-'));
87 let parts: Vec<&str> = slug.split('-').collect();
88 assert_eq!(parts.len(), 2);
89 assert!(ADJECTIVES.contains(&parts[0]));
90 assert!(NOUNS.contains(&parts[1]));
91 }
92
93 #[test]
94 fn test_create_timestamped() {
95 let slug = create_timestamped();
96 let parts: Vec<&str> = slug.split('-').collect();
97 assert_eq!(parts.len(), 3);
98 assert!(parts[0].parse::<u128>().is_ok());
99 }
100
101 #[test]
102 fn test_create_with_prefix() {
103 let slug = create_with_prefix("plan");
104 assert!(slug.starts_with("plan-"));
105 let parts: Vec<&str> = slug.split('-').collect();
106 assert_eq!(parts.len(), 3);
107 assert_eq!(parts[0], "plan");
108 }
109
110 #[test]
111 fn test_uniqueness() {
112 let slugs: Vec<String> = (0..100).map(|_| create()).collect();
113 let unique_count = slugs.iter().collect::<std::collections::HashSet<_>>().len();
114 assert!(unique_count > 50, "Expected mostly unique slugs");
115 }
116}