1use std::default::Default;
2use std::fmt;
3use std::result;
4
5use std::time::{SystemTime, SystemTimeError, UNIX_EPOCH};
6
7static DEFAULT_EPOCH: u64 = 1451602800;
9
10#[derive(Debug, Clone)]
11pub struct Config {
12 pub node_id_bits: i8,
13 pub sequence_bits: i8,
14 pub node_id: u64,
15 pub epoch: u64,
16}
17
18impl fmt::Display for Config {
19 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
20 write!(f, "config-{:x}-{:x}-{:x}", self.node_id_bits, self.node_id, self.sequence_bits)
21 }
22}
23
24#[derive(Debug)]
25pub struct CornFlake {
26 node_id: u64,
27 sequence: u64,
28 sequence_mask: u64,
29 last_timestamp: u64,
30 epoch: u64,
31 node_id_left_shift: i8,
32 timestamp_left_shift: i8,
33}
34
35impl fmt::Display for CornFlake {
36 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
37 write!(f, "flake-{:x}-{:x}-{:x}", self.last_timestamp, self.node_id, self.sequence)
38 }
39}
40
41#[derive(Debug)]
42pub enum CornFlakeConfigError {
43 TooFewTimestampBits,
44 NodeIdTooBig(u64),
45}
46
47#[derive(Debug)]
48pub enum CornFlakeError {
49 ClockMovedBackwards(SystemTimeError)
50}
51
52impl From<SystemTimeError> for CornFlakeError {
53 fn from(err: SystemTimeError) -> CornFlakeError {
54 CornFlakeError::ClockMovedBackwards(err)
55 }
56}
57
58impl fmt::Display for CornFlakeConfigError {
59 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
60 match *self {
61 CornFlakeConfigError::TooFewTimestampBits => write!(f, "TooFewTimestampBits (less then 41bit)"),
62 CornFlakeConfigError::NodeIdTooBig(ref id) => write!(f, "NodeIdTooBig: {}", id),
63 }
64 }
65}
66
67pub type CornFlakeConfigResult<T> = result::Result<T, CornFlakeConfigError>;
68pub type CornFlakeResult<T> = result::Result<T, CornFlakeError>;
69
70impl Default for Config {
71 fn default() -> Config {
72 Config {
73 node_id_bits: 10,
74 sequence_bits: 10,
75 node_id: 0,
76 epoch: DEFAULT_EPOCH,
77 }
78 }
79}
80
81impl CornFlake {
82 pub fn new(config: &Config) -> CornFlakeConfigResult<CornFlake> {
83 if config.node_id_bits + config.sequence_bits > 22 {
84 return Err(CornFlakeConfigError::TooFewTimestampBits);
85 }
86 if config.node_id > (1 << config.node_id_bits) {
87 return Err(CornFlakeConfigError::NodeIdTooBig(config.node_id));
88 }
89
90 Ok(CornFlake {
91 node_id: config.node_id,
92 sequence: 0,
93 last_timestamp: 0,
94 epoch: config.epoch,
95
96 node_id_left_shift: config.node_id_bits,
97 timestamp_left_shift: config.node_id_bits + config.sequence_bits,
98 sequence_mask: !0 ^ (!0 << config.sequence_bits),
99 })
100 }
101
102 #[inline]
103 fn epoch_timestamp(&self) -> CornFlakeResult<u64> {
104 let t = SystemTime::now().duration_since(UNIX_EPOCH)?;
105 Ok(((t.as_secs() - self.epoch) * 1000) + t.subsec_nanos() as u64 / 1000000)
106 }
107
108 #[inline]
109 fn til_next_ms(&self) -> CornFlakeResult<u64> {
110 let mut timestamp = self.epoch_timestamp()?;
111 while timestamp <= self.last_timestamp {
112 timestamp = self.epoch_timestamp()?;
113 }
114 Ok(timestamp)
115 }
116
117 pub fn node_id(&self) -> u64 {
118 self.node_id
119 }
120
121 pub fn next_id(&mut self) -> CornFlakeResult<u64> {
122 let mut timestamp = self.epoch_timestamp()?;
123
124 if timestamp == self.last_timestamp {
125 self.sequence = (self.sequence + 1) & self.sequence_mask;
126 if self.sequence == 0 {
127 timestamp = self.til_next_ms()?;
128 }
129 } else {
130 self.sequence = 0;
131 }
132
133 self.last_timestamp = timestamp;
134
135 Ok((timestamp << self.timestamp_left_shift) | (self.node_id << self.node_id_left_shift) | self.sequence)
136 }
137}
138
139
140#[cfg(test)]
141mod tests {
142 use super::Config;
143 use super::CornFlake;
144
145 #[test]
146 fn initialize_and_run_default() {
147 let c: Config = Default::default();
148 let mut f = CornFlake::new(&c).unwrap();
149
150 for _ in 1..1000000 {
151 println!("{} ", f.next_id().unwrap());
152 }
153 }
154}