rainbeam_shared/
snow.rs

1//! Almost Snowflake
2//!
3//! Random IDs which include timestamp information (like Twitter Snowflakes)
4//!
5//! IDs are generated with 41 bits of an epoch timestamp, 10 bits of a machine/server ID, and 12 bits of randomly generated numbers.
6//!
7//! ```
8//! tttttttttttttttttttttttttttttttttttttttttiiiiiiiiiirrrrrrrrrrrr...
9//! Timestamp                                ID        Seed
10//! ```
11use serde::{Serialize, Deserialize};
12use crate::epoch_timestamp;
13
14use num_bigint::BigInt;
15use rand::Rng;
16
17static SEED_LEN: usize = 12;
18// static ID_LEN: usize = 10;
19
20#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
21pub struct AlmostSnowflake(String);
22
23pub fn bigint(input: usize) -> BigInt {
24    BigInt::from(input)
25}
26
27impl AlmostSnowflake {
28    /// Create a new [`AlmostSnowflake`]
29    pub fn new(server_id: usize) -> Self {
30        // generate random bytes
31        let mut bytes = String::new();
32
33        let mut rng = rand::rng();
34        for _ in 1..=SEED_LEN {
35            bytes.push_str(&rng.random_range(0..10).to_string())
36        }
37
38        // build id
39        let mut id = bigint(epoch_timestamp(2024) as usize) << 22_u128;
40        id |= bigint((server_id % 1024) << 12);
41        id |= bigint((bytes.parse::<usize>().unwrap() + 1) % 4096);
42
43        // return
44        Self(id.to_string())
45    }
46}
47
48impl std::fmt::Display for AlmostSnowflake {
49    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50        write!(f, "{}", self.0)
51    }
52}