1use super::defs::{MAX_SEQ, MAX_TS, MAX_WID, TS_SHIFT, WID_SHIFT};
2use crate::errors::Error;
3use std::fmt;
4
5#[derive(Clone, Copy, Debug, Eq, PartialEq)]
6pub struct Id(i64);
7
8impl Id {
9 pub fn new(ts: u64, wid: u16, seq: u16) -> Self {
15 assert!(ts != 0);
17 assert!(ts <= MAX_TS);
19 assert!(wid <= MAX_WID);
20 assert!(seq <= MAX_SEQ);
21
22 Id((ts << TS_SHIFT) as i64
23 | i64::from(wid << WID_SHIFT)
24 | i64::from(seq))
25 }
26
27 #[cfg(feature = "const_fn")]
28 pub const fn nil() -> Self {
29 Id(0)
30 }
31
32 #[cfg(not(feature = "const_fn"))]
33 pub fn nil() -> Id {
34 Id(0)
35 }
36
37 pub fn from_i64(i: i64) -> Self {
39 if i <= 0 {
40 return Id::nil();
41 }
42
43 let u = i as u64;
44 let ts = u >> TS_SHIFT;
45 let wid = ((u >> WID_SHIFT) % (u64::from(MAX_WID) + 1)) as u16;
46 let seq = (u % (u64::from(MAX_SEQ) + 1)) as u16;
47
48 Id::new(ts, wid, seq)
49 }
50
51 pub fn from_slice(b: &[u8]) -> Result<Self, Error> {
52 const BYTES_LEN: usize = 8;
53 let len = b.len();
54
55 if len != BYTES_LEN {
56 return Err(Error::BytesError("bytes too short".to_owned()));
57 }
58
59 let i = i64::from(b[0]) << 56
60 | i64::from(b[1]) << 48
61 | i64::from(b[2]) << 40
62 | i64::from(b[3]) << 32
63 | i64::from(b[4]) << 24
64 | i64::from(b[5]) << 16
65 | i64::from(b[6]) << 8
66 | i64::from(b[7]);
67
68 Ok(Id(i))
69 }
70
71 pub fn as_bytes(self) -> [u8; 8] {
73 let b1: u8 = ((self.0 >> 56) & 0xff) as u8;
74 let b2: u8 = ((self.0 >> 48) & 0xff) as u8;
75 let b3: u8 = ((self.0 >> 40) & 0xff) as u8;
76 let b4: u8 = ((self.0 >> 32) & 0xff) as u8;
77 let b5: u8 = ((self.0 >> 24) & 0xff) as u8;
78 let b6: u8 = ((self.0 >> 16) & 0xff) as u8;
79 let b7: u8 = ((self.0 >> 8) & 0xff) as u8;
80 let b8: u8 = (self.0 & 0xff) as u8;
81
82 [b1, b2, b3, b4, b5, b6, b7, b8]
83 }
84
85 pub fn is_nil(self) -> bool {
86 self.0 == 0
87 }
88}
89
90impl fmt::LowerHex for Id {
91 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
92 write!(f, "{:x}", self.0)
93 }
94}
95
96impl fmt::UpperHex for Id {
97 #[inline]
98 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
99 write!(f, "{:X}", self.0)
100 }
101}
102
103impl Into<i64> for Id {
104 fn into(self) -> i64 {
105 self.0
106 }
107}
108
109impl<'a> Into<i64> for &'a Id {
110 fn into(self) -> i64 {
111 self.0
112 }
113}
114
115impl Into<Id> for i64 {
116 fn into(self) -> Id {
117 Id::from_i64(self)
118 }
119}
120
121impl<'a> Into<Id> for &'a i64 {
122 fn into(self) -> Id {
123 Id::from_i64(*self)
124 }
125}
126
127impl Default for Id {
128 #[inline]
129 fn default() -> Self {
130 Id::nil()
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::Id;
137
138 #[test]
139 #[should_panic]
140 fn test_bad_worker_id() {
141 let _id = Id::new(0, 1024, 0);
142 }
143
144 #[test]
145 fn test_id_nil() {
146 let id = Id::nil();
147
148 assert_eq!(id, 0.into());
149 }
150
151 #[test]
152 fn test_id_from_i64_success() {
153 let i = 18_427_598_719_680_512;
155 let id = Id::from_i64(i);
156
157 assert_eq!(i, id.into());
158
159 let i = 0;
161 let id = Id::from_i64(i);
162
163 assert_eq!(i, id.into());
164 }
165
166 #[test]
167 #[should_panic]
168 fn test_id_from_i64_fail() {
169 let i = 1;
171 let _ = Id::from_i64(i);
172 }
173
174 #[test]
175 fn test_id_from_i64_nil() {
176 let i: i64 = -1;
178 let id = Id::from_i64(i);
179
180 assert!(id.is_nil());
181
182 let i: i64 = 0;
184 let id = Id::from_i64(i);
185
186 assert!(id.is_nil());
187 }
188}