pub struct Snowflake<T: IdInt, const TS: u8, const WK: u8, const SQ: u8> { /* private fields */ }Expand description
Snowflake ID generator.
§Type Parameters
T: Output integer type (u32,i32,u64,i64)TS: Tick bits (ordering field)WK: Worker bits (0 for single-worker systems)SQ: Sequence bits
§Layout (MSB to LSB)
[tick: TS bits][worker: WK bits][sequence: SQ bits]§Compile-Time Validation
TS + WK + SQ <= T::BITSTS > 0SQ > 0
§Tick
The generator is tick-agnostic. The caller provides a raw u64 value
to next() which becomes the ordering field in the ID. Common choices:
- Milliseconds since an application epoch (
(now - epoch).as_millis() as u64) - Block number (blockchain)
- Logical clock / Lamport counter
The only requirement is that the value is monotonically non-decreasing.
§Example
use std::time::Instant;
use nexus_id::Snowflake64;
// 42 bits tick, 6 bits worker, 16 bits sequence
type TradingId = Snowflake64<42, 6, 16>;
let epoch = Instant::now();
let mut id_gen = TradingId::new(5);
let tick = (Instant::now() - epoch).as_millis() as u64;
let id: u64 = id_gen.next(tick).unwrap();Implementations§
Source§impl<T: IdInt, const TS: u8, const WK: u8, const SQ: u8> Snowflake<T, TS, WK, SQ>
impl<T: IdInt, const TS: u8, const WK: u8, const SQ: u8> Snowflake<T, TS, WK, SQ>
Sourcepub const SEQUENCE_MAX: u64
pub const SEQUENCE_MAX: u64
Maximum sequence value for this layout.
Sourcepub const WORKER_MAX: u64
pub const WORKER_MAX: u64
Maximum worker value for this layout.
Sourcepub const TIMESTAMP_MAX: u64
pub const TIMESTAMP_MAX: u64
Maximum timestamp value for this layout.
Sourcepub fn try_new(worker: u64) -> Result<Self, WorkerIdError>
pub fn try_new(worker: u64) -> Result<Self, WorkerIdError>
Create a new generator, returning an error if worker exceeds the
maximum for this generator’s WK bit width.
This is the non-panicking counterpart to new.
§Errors
Returns WorkerIdError if worker > WORKER_MAX.
§Example
use nexus_id::Snowflake64;
type MyId = Snowflake64<42, 6, 16>;
let id_gen = MyId::try_new(5).unwrap();
assert!(MyId::try_new(64).is_err()); // 6 bits = max 63Sourcepub fn next(&mut self, tick: u64) -> Result<T, SnowflakeError>
pub fn next(&mut self, tick: u64) -> Result<T, SnowflakeError>
Generate the next ID.
§Arguments
tick- Monotonically non-decreasing value for the ordering field. Typically(now - epoch).as_millis() as u64for time-based IDs, but can be any u64 sequence (block numbers, logical clocks, etc.).
§Errors
Returns SequenceExhausted if more than SEQUENCE_MAX IDs are
generated with the same tick value. This is a backpressure signal.
§Performance
This method is designed for hot-path usage:
- No syscalls (caller provides tick)
- No allocation
- Single predictable branch in the common case
§Example
use std::time::Instant;
use nexus_id::Snowflake64;
type MyId = Snowflake64<42, 6, 16>;
let epoch = Instant::now();
let mut id_gen = MyId::new(5);
// Snap time once per event loop iteration
let tick = (Instant::now() - epoch).as_millis() as u64;
// Generate IDs using that tick
let id1 = id_gen.next(tick).unwrap();
let id2 = id_gen.next(tick).unwrap();Sourcepub fn mixed(&mut self, tick: u64) -> Result<T, SnowflakeError>
pub fn mixed(&mut self, tick: u64) -> Result<T, SnowflakeError>
Generate a raw ID with Fibonacci-mixed bits for identity hashers.
Applies a Fibonacci multiply (bijective, ~1 cycle) to the raw ID,
producing output with uniform bit distribution. Use with identity
hashers (e.g., nohash-hasher) for optimal HashMap performance.
The mixing is NOT reversible from this raw integer — use
next_id() + SnowflakeId64::mixed() if you
need to unmix later.
§Example
use nexus_id::Snowflake64;
type OrderId = Snowflake64<42, 6, 16>;
let mut id_gen = OrderId::new(0);
let id = id_gen.mixed(42).unwrap();Sourcepub fn unpack(id: T) -> (u64, u64, u64)
pub fn unpack(id: T) -> (u64, u64, u64)
Unpack an ID into (timestamp, worker, sequence).
§Example
use nexus_id::Snowflake64;
type MyId = Snowflake64<42, 6, 16>;
let mut id_gen = MyId::new(5);
let id = id_gen.next(0).unwrap();
let (ts, worker, seq) = MyId::unpack(id);
assert_eq!(ts, 0);
assert_eq!(worker, 5);
assert_eq!(seq, 0);Source§impl<const TS: u8, const WK: u8, const SQ: u8> Snowflake<u64, TS, WK, SQ>
impl<const TS: u8, const WK: u8, const SQ: u8> Snowflake<u64, TS, WK, SQ>
Sourcepub fn next_id(
&mut self,
tick: u64,
) -> Result<SnowflakeId64<TS, WK, SQ>, SnowflakeError>
pub fn next_id( &mut self, tick: u64, ) -> Result<SnowflakeId64<TS, WK, SQ>, SnowflakeError>
Generate the next ID as a typed SnowflakeId64.
Same as next() but returns the newtype wrapper with
field extraction and mixing methods.
Sourcepub fn next_mixed(
&mut self,
tick: u64,
) -> Result<MixedId64<TS, WK, SQ>, SnowflakeError>
pub fn next_mixed( &mut self, tick: u64, ) -> Result<MixedId64<TS, WK, SQ>, SnowflakeError>
Generate a Fibonacci-mixed ID as a typed MixedId64.
The mixed ID can be unmixed back to the original via MixedId64::unmix().
Source§impl<const TS: u8, const WK: u8, const SQ: u8> Snowflake<u32, TS, WK, SQ>
impl<const TS: u8, const WK: u8, const SQ: u8> Snowflake<u32, TS, WK, SQ>
Sourcepub fn next_id(
&mut self,
tick: u64,
) -> Result<SnowflakeId32<TS, WK, SQ>, SnowflakeError>
pub fn next_id( &mut self, tick: u64, ) -> Result<SnowflakeId32<TS, WK, SQ>, SnowflakeError>
Generate the next ID as a typed SnowflakeId32.
Sourcepub fn next_mixed(
&mut self,
tick: u64,
) -> Result<MixedId32<TS, WK, SQ>, SnowflakeError>
pub fn next_mixed( &mut self, tick: u64, ) -> Result<MixedId32<TS, WK, SQ>, SnowflakeError>
Generate a Fibonacci-mixed ID as a typed MixedId32.