1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
use std::sync::{Arc, Mutex};
use std::time::{SystemTime, UNIX_EPOCH};
use rbatis::rbatis::Rbatis;

use crate::worker::worker_assigner;
use crate::bits_allocator;
use crate::config::rid_config;

pub struct UidGenerator {
    bits_allocator:  bits_allocator::BitsAllocator,
    config:          rid_config::UidConfig,
    worker_id:       i64,
    last_second:     Arc<Mutex<i64>>,
    sequence :       i64,
}

impl UidGenerator {
    //New create the default uid generator instance
    pub  async fn new(config: &rid_config::UidConfig, rb: Arc<Rbatis>) -> Self {
        let new_config = config.clone();
        let id_assigner = worker_assigner::Assigner::new(
            new_config.port.clone(),
            Arc::clone(&rb)
        );
        let allocator = bits_allocator::BitsAllocator::new(
            config.time_bits,
            config.worker_bits,
            config.seq_bits
        );
        let mut worker_id = id_assigner.assign_worker_id().await;

        if worker_id > allocator.max_worker_id {
            worker_id = worker_id % allocator.max_worker_id
        }

        return UidGenerator {
            bits_allocator: allocator,
            config: new_config,
            worker_id,
            last_second: Arc::new(Mutex::new(0)),
            sequence: 0,
        }
    }

    // get_uid generate the unique id
    pub fn get_uid(& mut self) -> i64 {
        let c = &self.config;
        return self.next_id(c.epoch_seconds, c.max_backward_seconds,c.enable_backward);
    }

    // parse_uid parse the generated unique id then get the meta information
    // +------+----------------------+----------------+-----------+
    // | sign |     delta seconds    | worker node id | sequence  |
    // +------+----------------------+----------------+-----------+
    //   1bit          30bits              7bits         13bits
    pub fn parse_uid(&self, uid: i64) -> String {
        let total_bits = bits_allocator::TOTAL_BITS;
        let sign_bits = self.bits_allocator.sign_bits;
        let timestamp_bits = self.bits_allocator.timestamp_bits;
        let worker_id_bits = self.bits_allocator.worker_id_bits;
        let sequence_bits = self.bits_allocator.sequence_bits;
        let allocate_total_bits = self.bits_allocator.allocate_total_bits;

        let sequence = (uid << (total_bits - sequence_bits)) >> (total_bits - sequence_bits);
        let worker_id = (uid << (timestamp_bits + sign_bits + total_bits - allocate_total_bits))
            >> (total_bits - worker_id_bits);
        let delta_seconds = uid >> (worker_id_bits + sequence_bits);

        // format as string
        return format!(
            r#"{{\"uid\":\"{}\",\"timestamp\":\"{}\",\"worker_id\":\"{}\",\"sequence\":\"{}\"}}"#,
            uid, self.config.epoch_seconds + delta_seconds, worker_id, sequence
        );
    }

    fn next_id(
        & mut self,
        epoch_seconds: i64,
        max_backward_seconds: i64,
        enable_backward: bool
    ) -> i64 {
        let mut last_second = self.last_second.lock().unwrap();
        let mut current_second = self.get_current_second(epoch_seconds);

        if current_second < *last_second {
            if !enable_backward {
                panic!("Clock moved backwards. But backward not enabled");
            }

            let refused_seconds = *last_second - current_second;
            if refused_seconds <= max_backward_seconds {
                while current_second < *last_second {
                    current_second = self.get_current_second(epoch_seconds)
                }
            } else {
                panic!("Clock moved backwards. Refused seconds bigger than max backward seconds")
            }
        } else if current_second == *last_second { // At the same second, increase sequence
            self.sequence = (self.sequence + 1) & self.bits_allocator.max_sequence;
            // Exceed the max sequence, we wait the next second to generate uid
            if self.sequence == 0 {
                current_second = self.get_next_second(*last_second, epoch_seconds);
            }
        } else {
            // At the different second, sequence restart from zero
            self.sequence = 0i64;
        }

        *last_second = current_second;

        // Allocate bits for uid
        self.bits_allocator.allocate(
            current_second - epoch_seconds,
            self.worker_id,
            self.sequence
        )
    }

    #[inline(always)]
    fn get_current_second(&self, epoch_seconds: i64) -> i64 {
        let current_seconds = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as i64;
        if current_seconds - epoch_seconds > self.bits_allocator.max_delta_seconds {
            panic!("Timestamp bits is exhausted. Refusing uid generation.")
        }

        return current_seconds
    }

    #[inline(always)]
    fn get_next_second(&self, last_timestamp: i64, epoch_seconds: i64) ->i64 {
        let mut timestamp = self.get_current_second(epoch_seconds);

        while timestamp <= last_timestamp {
            timestamp = self.get_current_second(epoch_seconds)
        }

        return timestamp
    }

}