ferrin_provider_util/
ids.rs1use rand::RngExt;
4
5pub const DEFAULT_ID_ALPHABET: &str =
7 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
8
9pub const DEFAULT_ID_SIZE: usize = 16;
11
12pub trait IdGenerator: Send + Sync {
16 fn generate(&self) -> String;
18}
19
20impl<F: Fn() -> String + Send + Sync> IdGenerator for F {
21 fn generate(&self) -> String {
22 self()
23 }
24}
25
26#[derive(Debug, Clone)]
28pub struct PrefixedIdGenerator {
29 prefix: Option<String>,
30 separator: char,
31 size: usize,
32 alphabet: &'static str,
33}
34
35impl PrefixedIdGenerator {
36 #[must_use]
38 pub fn new(prefix: impl Into<String>, size: usize) -> Self {
39 Self {
40 prefix: Some(prefix.into()),
41 separator: '-',
42 size,
43 alphabet: DEFAULT_ID_ALPHABET,
44 }
45 }
46
47 #[must_use]
49 pub fn unprefixed(size: usize) -> Self {
50 Self {
51 prefix: None,
52 separator: '-',
53 size,
54 alphabet: DEFAULT_ID_ALPHABET,
55 }
56 }
57
58 #[must_use]
60 pub fn with_separator(mut self, separator: char) -> Self {
61 self.separator = separator;
62 self
63 }
64
65 #[must_use]
67 pub fn prefix(&self) -> Option<&str> {
68 self.prefix.as_deref()
69 }
70}
71
72impl Default for PrefixedIdGenerator {
73 fn default() -> Self {
74 Self::unprefixed(DEFAULT_ID_SIZE)
75 }
76}
77
78impl IdGenerator for PrefixedIdGenerator {
79 fn generate(&self) -> String {
80 let random = random_string(self.size, self.alphabet);
81 match &self.prefix {
82 Some(prefix) => format!("{prefix}{}{random}", self.separator),
83 None => random,
84 }
85 }
86}
87
88#[must_use]
90pub fn generate_id() -> String {
91 random_string(DEFAULT_ID_SIZE, DEFAULT_ID_ALPHABET)
92}
93
94fn random_string(size: usize, alphabet: &str) -> String {
95 let chars: Vec<char> = alphabet.chars().collect();
96 let mut rng = rand::rng();
97 (0..size)
98 .map(|_| chars[rng.random_range(0..chars.len())])
99 .collect()
100}