#![allow(clippy::cast_possible_truncation)]
use crate::config::SnowIDConfig;
#[derive(Debug, Copy, Clone)]
pub struct SnowIDExtractor {
config: SnowIDConfig,
}
impl SnowIDExtractor {
pub(crate) const fn new(config: SnowIDConfig) -> Self {
Self { config }
}
#[inline(always)]
#[must_use]
pub const fn timestamp(&self, id: u64) -> u64 {
(id >> self.config.timestamp_shift()) & self.config.timestamp_mask()
}
#[inline(always)]
#[must_use]
pub fn node(&self, id: u64) -> u16 {
((id >> self.config.node_shift()) & u64::from(self.config.node_mask())) as u16
}
#[inline(always)]
#[must_use]
pub fn sequence(&self, id: u64) -> u16 {
(id & u64::from(self.config.sequence_mask())) as u16
}
#[inline]
#[must_use]
pub fn decompose(&self, id: u64) -> (u64, u16, u16) {
(self.timestamp(id), self.node(id), self.sequence(id))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::SnowID;
#[test]
fn test_decompose() {
let config = SnowIDConfig::default();
let snowid_gen = SnowID::with_config(42, config).unwrap();
let timestamp: u64 = 0x1234567;
let node: u16 = 42;
let sequence: u16 = 123;
let id = snowid_gen.create_snowid_with_node(timestamp, node, sequence);
assert_eq!(snowid_gen.extract.timestamp(id), timestamp);
assert_eq!(snowid_gen.extract.node(id), node);
assert_eq!(snowid_gen.extract.sequence(id), sequence);
let (ext_timestamp, ext_node, ext_sequence) = snowid_gen.extract.decompose(id);
assert_eq!(ext_timestamp, timestamp);
assert_eq!(ext_node, node);
assert_eq!(ext_sequence, sequence);
}
#[test]
fn test_component_boundaries() {
let config = SnowIDConfig::default();
let snowid_gen = SnowID::with_config(1, config).unwrap();
let max_timestamp = (1u64 << 42) - 1;
let max_node_id = config.max_node_id();
let max_sequence = config.max_sequence_id();
let id = snowid_gen.create_snowid_with_node(max_timestamp, max_node_id, max_sequence);
assert_eq!(snowid_gen.extract.timestamp(id), max_timestamp);
assert_eq!(snowid_gen.extract.node(id), max_node_id);
assert_eq!(snowid_gen.extract.sequence(id), max_sequence);
}
}