hyperflake_rs/
snowflake.rs

1use crate::helper::{get_valid_node_id, wait_until_next_timestamp, defaults};
2
3pub struct SnowflakeId {
4    node_id_bits: i32,
5    sequence_bits: i32,
6    epoch: u64,
7    last_timestamp: i64,
8    sequence: u32,
9    node_id: i32,
10    max_sequence: u32,
11}
12
13impl SnowflakeId {
14    pub fn new() -> Self {
15        let worker_id = defaults::WORKER_ID;
16        let node_id_bits = defaults::NODE_ID_BITS;
17        let sequence_bits = defaults::SEQUENCE_BITS;
18        let epoch = defaults::EPOCH;
19
20        let last_timestamp = -1;
21        let sequence = 0;
22        let node_id = get_valid_node_id(worker_id as f64, node_id_bits);
23        let max_sequence = (1 << sequence_bits) - 1;
24
25        SnowflakeId {
26            node_id_bits,
27            sequence_bits,
28            epoch,
29            last_timestamp,
30            sequence,
31            node_id,
32            max_sequence,
33        }
34    }
35
36    pub fn generate(&mut self) -> String {
37        let timestamp: i64 = std::time::SystemTime::now()
38            .duration_since(std::time::UNIX_EPOCH)
39            .unwrap()
40            .as_millis() as i64;
41
42        if timestamp < self.last_timestamp {
43            panic!("Clock is moving backwards!");
44        }
45
46        if timestamp == self.last_timestamp {
47            self.sequence = (self.sequence + 1) & self.max_sequence;
48            if self.sequence == 0 {
49                let new_timestamp = wait_until_next_timestamp(timestamp as u64);
50                self.last_timestamp = new_timestamp as i64;
51            }
52        } else {
53            self.sequence = 0;
54        }
55
56        self.last_timestamp = timestamp;
57
58        let high = ((timestamp - self.epoch as i64) << (self.node_id_bits + self.sequence_bits))
59            | ((self.node_id as i64) << self.sequence_bits)
60            | self.sequence as i64;
61
62        let snowflake_id = high;
63
64        snowflake_id.to_string()
65    }
66
67    pub fn decode(&self, hfid: &str) -> u64 {
68        let high = hfid.parse::<i64>().unwrap();
69        let timestamp = ((high >> (self.node_id_bits + self.sequence_bits)) + self.epoch as i64) as u64;
70        timestamp
71    }
72}