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#[derive(Debug, Default, PartialEq, Copy, Clone)]
10pub struct Snowflake {
11 pub timestamp: u64,
13 pub instance: u16,
15 pub sequence: u16,
17}
18
19impl Snowflake {
20 pub fn new(timestamp: u64, instance: u16, sequence: u16) -> Self {
22 Self {
23 timestamp,
24 instance,
25 sequence,
26 }
27 }
28
29 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 pub fn get_unix_timestamp(&self) -> u64 {
44 CONTEXT.epoch_start.load(Ordering::Relaxed) + self.timestamp
45 }
46
47 pub fn to_decimal(&self) -> i64 {
49 self.produce()
50 }
51
52 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}