randem/
lib.rs

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}