use super::constants::{
HOST_BITS,
HOST_MAX,
MODE_BITS,
PRECISION_BITS,
};
use super::{
IdMode,
TimestampPrecision,
};
use crate::IdError;
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct QubitSnowflakeBuilder {
mode: IdMode,
precision: TimestampPrecision,
host: u64,
mode_shift: u8,
timestamp_shift: u8,
precision_shift: u8,
host_shift: u8,
timestamp_bits: u8,
max_timestamp: u64,
max_sequence: u64,
fixed_data: u64,
}
impl QubitSnowflakeBuilder {
pub fn new(mode: IdMode, precision: TimestampPrecision, host: u64) -> Result<Self, IdError> {
if host > HOST_MAX {
return Err(IdError::HostOutOfRange {
host,
max: HOST_MAX,
});
}
Ok(Self::new_unchecked(mode, precision, host))
}
fn new_unchecked(mode: IdMode, precision: TimestampPrecision, host: u64) -> Self {
let timestamp_bits = precision.timestamp_bits();
let sequence_bits = precision.sequence_bits();
let max_timestamp = (1_u64 << timestamp_bits) - 1;
let max_sequence = (1_u64 << sequence_bits) - 1;
let mode_shift = u64::BITS as u8 - MODE_BITS;
let precision_shift = mode_shift - PRECISION_BITS;
let timestamp_shift = HOST_BITS + sequence_bits;
let host_shift = sequence_bits;
let fixed_data = (mode.ordinal() << mode_shift)
| (precision.ordinal() << precision_shift)
| (host << host_shift);
Self {
mode,
precision,
host,
mode_shift,
timestamp_shift,
precision_shift,
host_shift,
timestamp_bits,
max_timestamp,
max_sequence,
fixed_data,
}
}
pub const fn mode(&self) -> IdMode {
self.mode
}
pub const fn precision(&self) -> TimestampPrecision {
self.precision
}
pub const fn host(&self) -> u64 {
self.host
}
pub const fn max_timestamp(&self) -> u64 {
self.max_timestamp
}
pub const fn max_sequence(&self) -> u64 {
self.max_sequence
}
pub fn build(&self, timestamp: u64, sequence: u64) -> Result<u64, IdError> {
if timestamp > self.max_timestamp {
return Err(IdError::TimestampOverflow {
timestamp,
max: self.max_timestamp,
});
}
if sequence > self.max_sequence {
return Err(IdError::SequenceOverflow {
sequence,
max: self.max_sequence,
});
}
let stored_timestamp = match self.mode {
IdMode::Sequential => timestamp,
IdMode::Spread => timestamp.reverse_bits() >> (u64::BITS as u8 - self.timestamp_bits),
};
Ok((stored_timestamp << self.timestamp_shift) | self.fixed_data | sequence)
}
pub fn extract_mode(&self, id: u64) -> IdMode {
let bit = (id >> self.mode_shift) & ((1_u64 << MODE_BITS) - 1);
IdMode::from_bit(bit)
}
pub fn extract_timestamp(&self, id: u64) -> u64 {
let timestamp = (id >> self.timestamp_shift) & self.max_timestamp;
match self.mode {
IdMode::Sequential => timestamp,
IdMode::Spread => timestamp.reverse_bits() >> (u64::BITS as u8 - self.timestamp_bits),
}
}
pub fn extract_precision(&self, id: u64) -> TimestampPrecision {
let bit = (id >> self.precision_shift) & ((1_u64 << PRECISION_BITS) - 1);
TimestampPrecision::from_bit(bit)
}
pub fn extract_host(&self, id: u64) -> u64 {
(id >> self.host_shift) & ((1_u64 << HOST_BITS) - 1)
}
pub fn extract_sequence(&self, id: u64) -> u64 {
id & self.max_sequence
}
}
impl Default for QubitSnowflakeBuilder {
fn default() -> Self {
Self::new_unchecked(IdMode::Sequential, TimestampPrecision::Second, 0)
}
}