icechip/
lib.rs

1use tinyrand::{Rand, StdRand};
2
3use std::time::{SystemTime, UNIX_EPOCH};
4
5#[derive(Clone, Debug)]
6pub enum Version {
7    ENHANCED,
8    EXTENDED,
9}
10
11#[derive(Clone, Debug)]
12pub struct Icechip<T> {
13    version: Version,
14    timestamp: T,
15    machine_id: T,
16    sequence: T,
17    epoch: Option<u128>,
18}
19
20impl Into<u64> for Icechip<u64> {
21    fn into(self) -> u64 {
22        let mut ret: u64 = self.timestamp.wrapping_shl(23);
23        ret = ret + self.machine_id.wrapping_shl(12);
24        ret = ret + self.sequence;
25        return ret;
26    }
27}
28
29impl From<u64> for Icechip<u64> {
30    fn from(value: u64) -> Icechip<u64> {
31        return Icechip {
32            version: Version::ENHANCED,
33            timestamp: value.wrapping_shr(23),
34            machine_id: value.wrapping_shl(41).wrapping_shr(53),
35            sequence: value.wrapping_shl(52).wrapping_shr(52),
36            epoch: None,
37        };
38    }
39}
40
41impl Into<u128> for Icechip<u128> {
42    fn into(self) -> u128 {
43        let mut ret: u128 = self.timestamp.wrapping_shl(64);
44        ret = ret + self.machine_id.wrapping_shl(32);
45        ret = ret + self.sequence;
46        return ret;
47    }
48}
49
50impl From<u128> for Icechip<u128> {
51    fn from(value: u128) -> Icechip<u128> {
52        return Icechip {
53            version: Version::EXTENDED,
54            timestamp: value.wrapping_shr(64),
55            machine_id: value.wrapping_shr(32).wrapping_shl(64).wrapping_shr(64),
56            sequence: value.wrapping_shl(96).wrapping_shr(96),
57            epoch: None,
58        };
59    }
60}
61
62impl<T: Clone> Icechip<T> {
63    pub fn set_epoch(mut self, epoch: u128) {
64        self.epoch = Some(epoch);
65    }
66
67    pub fn timestamp(&self) -> T {
68        return self.timestamp.clone();
69    }
70
71    pub fn machine_id(&self) -> T {
72        return self.machine_id.clone();
73    }
74
75    pub fn sequence(&self) -> T {
76        return self.sequence.clone();
77    }
78
79    pub fn version(&self) -> Version {
80        return self.version.clone();
81    }
82}
83
84impl Icechip<u64> {
85    pub fn new(epoch: Option<u128>) -> Icechip<u64> {
86        let mut rand = StdRand::default();
87        return Icechip {
88            version: Version::ENHANCED,
89            timestamp: 0,
90            machine_id: rand.next_u64().wrapping_shl(41).wrapping_shr(53),
91            sequence: 0,
92            epoch,
93        }
94        .tick();
95    }
96
97    pub fn tick(&self) -> Icechip<u64> {
98        match SystemTime::now().duration_since(UNIX_EPOCH) {
99            Ok(o) => {
100                let o = o.as_millis();
101                let curr_ts = match self.epoch {
102                    Some(s) => (o - s).wrapping_shl(23).wrapping_shr(23) as u64,
103                    None => o.wrapping_shl(23).wrapping_shr(23) as u64,
104                };
105                if self.timestamp == curr_ts {
106                    if (self.sequence + 1) > 1023 {
107                        std::thread::sleep(std::time::Duration::from_millis(1));
108                        return self.tick();
109                    } else {
110                        return Icechip {
111                            version: self.version.clone(),
112                            timestamp: self.timestamp.clone(),
113                            machine_id: self.machine_id.clone(),
114                            sequence: self.sequence.clone() + 1,
115                            epoch: self.epoch.clone(),
116                        };
117                    }
118                } else {
119                    return Icechip {
120                        version: self.version.clone(),
121                        timestamp: curr_ts.clone(),
122                        machine_id: self.machine_id.clone(),
123                        sequence: 0,
124                        epoch: self.epoch.clone(),
125                    };
126                }
127            }
128            Err(_) => {
129                std::thread::sleep(std::time::Duration::from_millis(1));
130                return self.tick();
131            }
132        }
133    }
134
135    pub fn with_id(machine_id: u64, epoch: Option<u128>) -> Icechip<u64> {
136        return Icechip {
137            version: Version::ENHANCED,
138            timestamp: 0,
139            machine_id,
140            sequence: 0,
141            epoch,
142        }
143        .tick();
144    }
145
146    pub fn to_u64(self) -> u64 {
147        return Into::<u64>::into(self);
148    }
149}
150
151impl Icechip<u128> {
152    pub fn new(epoch: Option<u128>) -> Icechip<u128> {
153        let mut rand = StdRand::default();
154        return Icechip {
155            version: Version::EXTENDED,
156            timestamp: 0,
157            machine_id: rand.next_u128(),
158            sequence: 0,
159            epoch,
160        }
161        .tick();
162    }
163
164    pub fn tick(&self) -> Icechip<u128> {
165        match SystemTime::now().duration_since(UNIX_EPOCH) {
166            Ok(o) => {
167                let o = o.as_millis();
168                let curr_ts = match self.epoch {
169                    Some(s) => o - s as u128,
170                    None => o,
171                };
172                if self.timestamp == curr_ts {
173                    if (self.sequence + 1) > u32::MAX as u128 {
174                        std::thread::sleep(std::time::Duration::from_millis(1));
175                        return self.tick();
176                    } else {
177                        return Icechip {
178                            version: self.version.clone(),
179                            timestamp: self.timestamp.clone(),
180                            machine_id: self.machine_id.clone(),
181                            sequence: self.sequence.clone() + 1,
182                            epoch: self.epoch.clone(),
183                        };
184                    }
185                } else {
186                    return Icechip {
187                        version: self.version.clone(),
188                        timestamp: o.clone(),
189                        machine_id: self.machine_id.clone(),
190                        sequence: 0,
191                        epoch: self.epoch.clone(),
192                    };
193                }
194            }
195            Err(_) => {
196                std::thread::sleep(std::time::Duration::from_millis(1));
197                return self.tick();
198            }
199        }
200    }
201
202    pub fn with_id(machine_id: u128, epoch: Option<u128>) -> Icechip<u128> {
203        return Icechip {
204            version: Version::EXTENDED,
205            timestamp: 0,
206            machine_id,
207            sequence: 0,
208            epoch,
209        }
210        .tick();
211    }
212
213    pub fn to_u128(self) -> u128 {
214        return Into::<u128>::into(self);
215    }
216}
217
218#[cfg(test)]
219mod tests {
220    use super::*;
221
222    #[test]
223    fn from_into_u128() {
224        let test_chip = Icechip::from(1234567890u128);
225        assert_eq!(1234567890u128, test_chip.into());
226    }
227
228    #[test]
229    fn from_into_u64() {
230        let test_chip = Icechip::from(1234567890u64);
231        assert_eq!(1234567890u64, test_chip.into());
232    }
233
234    #[test]
235    fn custom_machine_id_u128() {
236        let test_chip = Icechip::<u128>::with_id(1u128, None);
237        test_chip.tick();
238        assert_eq!(test_chip.machine_id(), 1u128);
239    }
240
241    #[test]
242    fn custom_machine_id_u64() {
243        let test_chip = Icechip::<u64>::with_id(1u64, None);
244        test_chip.tick();
245        assert_eq!(test_chip.machine_id(), 1u64);
246    }
247
248    #[test]
249    fn tick_u128() {
250        let test_chip = Icechip::<u128>::new(None);
251        println!("test: {:#b}", test_chip.clone().to_u128());
252        let ticked_chip = test_chip.tick();
253        println!("tick: {:#b}", ticked_chip.clone().to_u128());
254        assert!(test_chip.clone().to_u128() < ticked_chip.to_u128());
255    }
256
257    #[test]
258    fn tick_u64() {
259        let test_chip = Icechip::<u64>::new(None);
260        println!("test: {:#b}", test_chip.clone().to_u64());
261        let ticked_chip = test_chip.tick();
262        println!("tick: {:#b}", ticked_chip.clone().to_u64());
263        assert!(test_chip.clone().to_u64() < ticked_chip.to_u64());
264    }
265}