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}