cuid2_timeless/
generator.rs1#[cfg(feature = "random")]
2use rand::{self, Rng};
3
4use crate::{
5 errors,
6 utils,
7};
8
9pub const INITIAL_COUNT_MAX: usize = 476782367;
12pub const DEFAULT_LENGTH: usize = 24;
14pub const MAXIMUM_LENGTH: usize = 98;
16
17pub struct Cuid {
19 random: utils::RandomFunctionType,
20 counter: utils::CounterFunctionType,
21 length: usize,
22 fingerprint: String,
23}
24
25#[cfg(feature = "random")]
26impl Default for Cuid {
27 fn default() -> Self {
28 let mut randomity = rand::thread_rng();
29 let randomed: f64 = randomity.gen();
30 let mut wrapper_rand: Box<dyn FnMut() -> f64> = Box::new(move || randomity.gen());
31 Cuid {
32 fingerprint: utils::create_fingerprint(&mut wrapper_rand, None),
33 random: wrapper_rand,
34 counter: Box::new(utils::create_counter(
35 (randomed * INITIAL_COUNT_MAX as f64) as isize,
36 )),
37 length: DEFAULT_LENGTH,
38 }
39 }
40}
41
42impl Cuid {
43 #[inline]
44 pub fn new(
46 mut random: utils::RandomFunctionType,
47 counter: utils::CreateCounterFunctionType,
48 length: usize,
49 fingerprint: utils::FingerPrintFunctionType,
50 ) -> Self {
51 let randomed = random();
52 let created = counter((randomed * INITIAL_COUNT_MAX as f64) as isize);
53 Cuid {
54 fingerprint: fingerprint(&mut random, None),
55 random,
56 counter: created,
57 length,
58 }
59 }
60 #[inline]
61 pub fn generate(&mut self, length: Option<usize>) -> Result<String, errors::Errors> {
63 let actual_length = length.unwrap_or(self.length);
64 if actual_length > MAXIMUM_LENGTH {
65 return Err(errors::Errors::ExceededMaximumLengthGenerateCuidError);
66 }
67
68 let first_letter = utils::create_letter(&mut self.random);
69
70 let base36_time = utils::base36_encode(
71 std::time::SystemTime::now()
72 .duration_since(std::time::UNIX_EPOCH)
73 .unwrap()
74 .as_nanos()
75 .into(),
76 );
77 let base36_count = utils::base36_encode(((self.counter)() as usize).into());
78
79 let salt = match utils::create_entropy(&mut self.random, Some(actual_length))
80 .map_err(|_| errors::Errors::LessThanOneEntropyError)
81 {
82 Ok(s) => s,
83 Err(e) => {
84 return Err(e);
85 }
86 };
87 let hash_input = base36_time + &salt + &base36_count + &self.fingerprint;
88
89 return Ok(first_letter.to_string()
90 + &utils::create_hash(Some(hash_input))[0..actual_length]);
91 }
92}
93
94#[cfg(feature = "random")]
95pub fn cuid_wrapper() -> Box<dyn FnMut() -> Result<String, errors::Errors>> {
97 let mut cuid = Cuid::default();
98 return Box::new(move || cuid.generate(None));
99}