Skip to main content

Snowflake

Struct Snowflake 

Source
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::BITS
  • TS > 0
  • SQ > 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>

Source

pub const SEQUENCE_MAX: u64

Maximum sequence value for this layout.

Source

pub const WORKER_MAX: u64

Maximum worker value for this layout.

Source

pub const TIMESTAMP_MAX: u64

Maximum timestamp value for this layout.

Source

pub fn new(worker: u64) -> Self

Create a new generator.

§Arguments
  • worker - Worker ID, must fit in WK bits
§Panics

Panics if worker > WORKER_MAX. Use try_new for a non-panicking constructor.

§Example
use nexus_id::Snowflake64;

type MyId = Snowflake64<42, 6, 16>;

let mut id_gen = MyId::new(5);
Source

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 63
Source

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 u64 for 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();
Source

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();
Source

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

pub const fn worker(&self) -> u64

Worker ID for this generator.

Source

pub const fn sequence(&self) -> u64

Current sequence within this millisecond.

Source

pub const fn last_tick(&self) -> u64

Last tick value used.

Source§

impl<const TS: u8, const WK: u8, const SQ: u8> Snowflake<u64, TS, WK, SQ>

Source

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.

Source

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>

Source

pub fn next_id( &mut self, tick: u64, ) -> Result<SnowflakeId32<TS, WK, SQ>, SnowflakeError>

Generate the next ID as a typed SnowflakeId32.

Source

pub fn next_mixed( &mut self, tick: u64, ) -> Result<MixedId32<TS, WK, SQ>, SnowflakeError>

Generate a Fibonacci-mixed ID as a typed MixedId32.

Trait Implementations§

Source§

impl<T: Clone + IdInt, const TS: u8, const WK: u8, const SQ: u8> Clone for Snowflake<T, TS, WK, SQ>

Source§

fn clone(&self) -> Snowflake<T, TS, WK, SQ>

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T: Debug + IdInt, const TS: u8, const WK: u8, const SQ: u8> Debug for Snowflake<T, TS, WK, SQ>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<T, const TS: u8, const WK: u8, const SQ: u8> Freeze for Snowflake<T, TS, WK, SQ>
where PhantomData<T>: Freeze,

§

impl<T, const TS: u8, const WK: u8, const SQ: u8> RefUnwindSafe for Snowflake<T, TS, WK, SQ>

§

impl<T, const TS: u8, const WK: u8, const SQ: u8> Send for Snowflake<T, TS, WK, SQ>
where PhantomData<T>: Send,

§

impl<T, const TS: u8, const WK: u8, const SQ: u8> Sync for Snowflake<T, TS, WK, SQ>
where PhantomData<T>: Sync,

§

impl<T, const TS: u8, const WK: u8, const SQ: u8> Unpin for Snowflake<T, TS, WK, SQ>
where PhantomData<T>: Unpin,

§

impl<T, const TS: u8, const WK: u8, const SQ: u8> UnsafeUnpin for Snowflake<T, TS, WK, SQ>

§

impl<T, const TS: u8, const WK: u8, const SQ: u8> UnwindSafe for Snowflake<T, TS, WK, SQ>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.