1use emoji::{self, Emoji};
2use rand::seq::IteratorRandom;
3use rand::SeedableRng;
4use std::collections::hash_map::DefaultHasher;
5use std::hash::{Hash, Hasher};
6
7fn hash_string(s: &str) -> u64 {
8 let mut hasher = DefaultHasher::new();
9 s.hash(&mut hasher);
10 hasher.finish()
11}
12
13pub fn randem(
14 seed: Option<String>,
15 include_group: Option<String>,
16 exclude_group: Option<String>,
17) -> String {
18 let mut rng = if let Some(seed) = seed {
19 let hashed = hash_string(&seed);
20 rand::rngs::StdRng::seed_from_u64(hashed)
21 } else {
22 rand::rngs::StdRng::from_entropy()
23 };
24
25 let include_group = include_group.map(|s| s.to_lowercase());
26 let exclude_group = exclude_group.map(|s| s.to_lowercase());
27
28 let emoji_filter = |e: &Emoji| {
29 if let Some(include_group) = &include_group {
30 e.group.to_lowercase().contains(include_group)
31 || e.name.to_lowercase().contains(include_group)
32 } else if let Some(exclude_group) = &exclude_group {
33 !(e.group.to_lowercase().contains(exclude_group)
34 || e.name.to_lowercase().contains(exclude_group))
35 } else {
36 true
37 }
38 };
39
40 let all_emoji: Vec<&Emoji> = emoji::lookup_by_name::iter_emoji().collect();
41 all_emoji
42 .into_iter()
43 .filter(|e| emoji_filter(e))
44 .choose(&mut rng)
45 .map(|e| e.glyph.to_string())
46 .unwrap_or_else(|| "".to_string())
47}