snowflake-gen 1.0.0

A configurable Snowflake ID generator with custom bit layouts, thread-local global generation, and ID decomposition
Documentation
  • Coverage
  • 71.43%
    50 out of 70 items documented13 out of 38 items with examples
  • Size
  • Source code size: 47.27 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 4.01 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 1m 15s Average build duration of successful builds.
  • all releases: 1m 26s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • Repository
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • koalacodee

snowflake-gen

A configurable Snowflake ID generator for Rust.

Features

  • Configurable bit layout -- tune the balance between timestamp range, throughput, and node count
  • Thread-local global API -- zero-lock, zero-contention ID generation across threads
  • ID decomposition -- decode any generated ID back into its timestamp, machine, node, and sequence parts
  • Buffered generation -- SnowflakeIdBucket pre-generates a full sequence batch for maximum throughput
  • Custom epochs -- use Discord-style, Twitter-style, or your own epoch

Default layout (Twitter-compatible)

Field Bits Max value
Timestamp 41 ~69 years
Machine ID 5 31
Node ID 5 31
Sequence 12 4,096/ms

Quick start

use snowflake_gen::SnowflakeIdGenerator;

let mut idgen= SnowflakeIdGenerator::new(1, 1).unwrap();
let id = idgen.generate().unwrap();
println!("{id}");

Custom bit layout

use snowflake_gen::{BitLayout, SnowflakeIdGenerator};

// 10 sequence bits (1,023 IDs/ms), 8 machine + 7 node bits
let layout = BitLayout::new(38, 8, 7, 10).unwrap();
let mut idgen= SnowflakeIdGenerator::with_layout(1, 1, layout).unwrap();
let id = idgen.generate().unwrap();

Thread-local global API

Initialize once, then call next_id() from any thread with no locking:

use snowflake_gen::{BitLayout, init, next_id};

fn main() {
    init(1, BitLayout::default()).unwrap();

    let id = next_id().unwrap();
    println!("{id}");
}

Each thread gets its own generator with a unique node_id assigned automatically.

ID decomposition

use snowflake_gen::SnowflakeIdGenerator;

let mut idgen= SnowflakeIdGenerator::new(3, 7).unwrap();
let id = idgen.generate().unwrap();
let parts = idgen.decompose(id);

assert_eq!(parts.machine_id, 3);
assert_eq!(parts.node_id, 7);

Buffered generation

SnowflakeIdBucket pre-generates a full sequence cycle and serves IDs from a buffer:

use snowflake_gen::SnowflakeIdBucket;

let mut bucket = SnowflakeIdBucket::new(1, 1).unwrap();
let id = bucket.get_id();

Caveats

  • Thread count is limited by node_id_bits. Each thread that calls next_id() is assigned a unique node ID. With the default 5 node_id_bits, at most 32 threads can generate IDs. Exceeding this returns SnowflakeError::NodeIdExhausted. If your application needs more threads, increase node_id_bits (and reduce machine_id_bits or timestamp_bits to compensate) when constructing your BitLayout.
  • init() can only be called once per process. A second call returns SnowflakeError::AlreadyInitialized. Thread-local generators created by earlier threads retain the original configuration and cannot be updated in-place. To change the configuration, restart the process so all thread-local state is cleared and recreated.
  • Do not mix lazy_generate with clock-based methods (generate / real_time_generate) on the same generator instance. lazy_generate advances the internal timestamp synthetically, so a later clock-based call may reuse a timestamp that lazy_generate already claimed, producing duplicate IDs. SnowflakeIdBucket uses lazy_generate internally on a dedicated generator and is safe to use alongside separate clock-based generators.

License

MIT