cornflake/
lib.rs

1use std::default::Default;
2use std::fmt;
3use std::result;
4
5use std::time::{SystemTime, SystemTimeError, UNIX_EPOCH};
6
7// DEFAULT_EPOCH is 2016-01-01T00:00:00.000
8static 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}