k_snowflake/
snowflake.rs

1use crate::constants::*;
2use crate::context::{sequence_increment, CONTEXT};
3use crate::utils::time_since_epoch;
4use std::fmt;
5use std::str::FromStr;
6use std::sync::atomic::Ordering;
7
8/// Snowflake structure
9#[derive(Debug, Default, PartialEq, Copy, Clone)]
10pub struct Snowflake {
11    /// Timestamp in ms since snowflake epoch start
12    pub timestamp: u64,
13    /// Instance of the snowflake (see schema in readme)
14    pub instance: u16,
15    /// Sequence of the snowflake (see schema in readme)
16    pub sequence: u16,
17}
18
19impl Snowflake {
20    /// New snowflake
21    pub fn new(timestamp: u64, instance: u16, sequence: u16) -> Self {
22        Self {
23            timestamp,
24            instance,
25            sequence,
26        }
27    }
28
29    /// New snowflake based on context values
30    pub fn from_context() -> Self {
31        let snowflake = Snowflake::new(
32            time_since_epoch(CONTEXT.epoch_start.load(Ordering::Relaxed)),
33            CONTEXT.instance.load(Ordering::Relaxed),
34            CONTEXT.sequence.load(Ordering::Relaxed),
35        );
36        if CONTEXT.sequence_autoincrement.load(Ordering::Relaxed) {
37            sequence_increment();
38        }
39        snowflake
40    }
41
42    /// Return UNIX timestamp in ms of snowflake
43    pub fn get_unix_timestamp(&self) -> u64 {
44        CONTEXT.epoch_start.load(Ordering::Relaxed) + self.timestamp
45    }
46
47    /// Return decimal value of snowflake
48    pub fn to_decimal(&self) -> i64 {
49        self.produce()
50    }
51
52    /// Return binary string of snowflake
53    pub fn to_bin(&self) -> String {
54        format!("{:b}", self.produce()).to_string()
55    }
56
57    fn produce(&self) -> i64 {
58        let mut snowflake = self.timestamp as i64;
59        snowflake <<= INSTANCE_BYTES;
60        snowflake |= (self.instance & 0x3FF) as i64;
61        snowflake <<= SEQUENCE_BYTES;
62        snowflake |= (self.sequence & 0xFFF) as i64;
63        snowflake
64    }
65}
66
67impl fmt::Display for Snowflake {
68    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69        write!(f, "{}", self.to_decimal())
70    }
71}
72
73impl fmt::Binary for Snowflake {
74    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75        write!(f, "{}", self.to_bin())
76    }
77}
78
79#[derive(Debug)]
80pub struct SnowflakeParseError;
81
82impl FromStr for Snowflake {
83    type Err = SnowflakeParseError;
84
85    fn from_str(s: &str) -> Result<Self, Self::Err> {
86        let mut snowflake: i64 = s.parse().map_err(|_| SnowflakeParseError)?;
87
88        let sequence = (snowflake & 0xFFF) as u16;
89        snowflake >>= SEQUENCE_BYTES;
90        let instance = (snowflake & 0x3FF) as u16;
91        snowflake >>= INSTANCE_BYTES;
92        let timestamp = snowflake as u64;
93
94        Ok(Self {
95            timestamp,
96            instance,
97            sequence,
98        })
99    }
100}