Skip to main content

Snowflake

Struct Snowflake 

Source
pub struct Snowflake { /* private fields */ }
Available on crate feature snowflake only.
Expand description

Snowflake ID generator.

Holds the worker ID, the epoch, and the packed (last_ms, next_seq) state used to mint monotonic IDs lock-free.

§Example

use id_forge::snowflake::Snowflake;

let gen = Snowflake::new(7);
let id = gen.next_id();
assert_eq!(Snowflake::parts(id).1, 7);

Implementations§

Source§

impl Snowflake

Source

pub const fn new(worker_id: u16) -> Self

Build a new generator with the given worker ID (0-1023) and the default 2026-01-01 epoch.

Worker IDs above 1023 are silently clamped to 10 bits.

§Example
use id_forge::snowflake::Snowflake;

let gen = Snowflake::new(42);
assert_eq!(gen.worker_id(), 42);
Examples found in repository?
examples/bench.rs (line 42)
33fn main() {
34    println!("id-forge throughput (single thread, release build)");
35    println!("---------------------------------------------------");
36
37    let iters = 1_000_000;
38    bench("Uuid::v4", iters, Uuid::v4);
39    bench("Uuid::v7", iters, Uuid::v7);
40    bench("Ulid::new", iters, Ulid::new);
41
42    let sf = Snowflake::new(1);
43    bench("Snowflake::next_id", iters, || sf.next_id());
44
45    bench("nanoid::generate", iters / 5, nanoid::generate);
46    bench("nanoid::with_length(8)", iters / 5, || {
47        nanoid::with_length(8)
48    });
49    bench("nanoid::custom(16, hex)", iters / 5, || {
50        nanoid::custom(16, b"0123456789abcdef")
51    });
52    bench("nanoid::custom(21, 17-char)", iters / 5, || {
53        nanoid::custom(21, b"ABCDEFGHIJKLMNOPQ")
54    });
55}
More examples
Hide additional examples
examples/basic.rs (line 18)
7fn main() {
8    let v4 = Uuid::v4();
9    println!("UUID v4:    {v4} (version={})", v4.version());
10    println!("UUID v7:    {}", Uuid::v7());
11    println!("UUID nil:   {}", Uuid::nil());
12
13    let a = Ulid::new();
14    let b = Ulid::new();
15    println!("ULID a:     {a}");
16    println!("ULID b:     {b} (monotonic: {})", b > a);
17
18    let gen = Snowflake::new(1);
19    let sf = gen.next_id();
20    let (ts_offset, worker, seq) = Snowflake::parts(sf);
21    println!(
22        "Snowflake:  {sf}  (ts+epoch={}, worker={worker}, seq={seq})",
23        ts_offset + gen.epoch_ms()
24    );
25
26    println!("NanoID 21:  {}", nanoid::generate());
27    println!("NanoID 8:   {}", nanoid::with_length(8));
28
29    assert_eq!(v4, Uuid::parse_str(&v4.to_string()).unwrap());
30    assert_eq!(a, Ulid::parse_str(&a.to_string()).unwrap());
31}
examples/snowflake_clock_skew.rs (line 22)
21fn main() {
22    let gen = Snowflake::new(1);
23
24    println!("== Normal path ==");
25    match gen.try_next_id() {
26        Ok(id) => println!("ok: id = {id}"),
27        Err(e) => println!("err: {e}"),
28    }
29
30    println!("\n== Recovering from a transient skew ==");
31    // Real services will see this when an NTP correction nudges the
32    // clock backward by a millisecond or two. The recommended
33    // strategy is: short pause, then retry. After at most ~1ms the
34    // wall clock is ahead of `last_ms` again and try_next_id
35    // returns Ok.
36    let mut attempts = 0usize;
37    let id = loop {
38        attempts += 1;
39        match gen.try_next_id() {
40            Ok(id) => break id,
41            Err(ClockSkew { last_ms, now_ms }) => {
42                // Backoff proportional to how far we regressed.
43                let drift = last_ms.saturating_sub(now_ms);
44                eprintln!("skew detected, drift = {drift} ms; backing off");
45                std::thread::sleep(Duration::from_millis(drift.max(1) + 1));
46                if attempts > 16 {
47                    panic!("clock failed to recover after {attempts} attempts");
48                }
49            }
50        }
51    };
52    println!("recovered    = {id} after {attempts} attempt(s)");
53
54    println!("\n== Burst rate ==");
55    // The CAS state machine handles contention without locks. A
56    // single-thread tight loop here is the uncontended path.
57    let start = std::time::Instant::now();
58    let burst = 100_000;
59    for _ in 0..burst {
60        let _ = gen.next_id();
61    }
62    let elapsed = start.elapsed();
63    println!(
64        "{burst} IDs in {elapsed:?} ({:.0} ns/op)",
65        elapsed.as_nanos() as f64 / burst as f64
66    );
67}
examples/snowflake_distributed.rs (line 20)
18fn main() {
19    println!("== Default epoch (2026-01-01) ==");
20    let gen = Snowflake::new(7);
21    let id = gen.next_id();
22    let (ts_offset, worker, seq) = Snowflake::parts(id);
23    let wall_ms = ts_offset + gen.epoch_ms();
24    println!("id           = {id}");
25    println!("worker       = {worker}");
26    println!("seq          = {seq}");
27    println!("ts_offset_ms = {ts_offset}");
28    println!("wall_ms      = {wall_ms}");
29    println!("default epoch = {DEFAULT_EPOCH_MS}");
30
31    println!("\n== Twitter's original 2010 epoch ==");
32    let twitter_epoch_ms = 1_288_834_974_657;
33    let tw = Snowflake::with_epoch(9, twitter_epoch_ms);
34    let tw_id = tw.next_id();
35    let (tw_ts, tw_worker, _) = Snowflake::parts(tw_id);
36    println!("id           = {tw_id}");
37    println!("worker       = {tw_worker}");
38    println!("ts_offset_ms = {tw_ts}");
39    println!("wall_ms      = {}", tw_ts + tw.epoch_ms());
40
41    println!("\n== Multi-thread contention (8 threads x 2000 IDs) ==");
42    let gen = Arc::new(Snowflake::new(3));
43    let handles: Vec<_> = (0..8)
44        .map(|_| {
45            let g = Arc::clone(&gen);
46            thread::spawn(move || (0..2000).map(|_| g.next_id()).collect::<Vec<_>>())
47        })
48        .collect();
49
50    let mut all = HashSet::new();
51    for h in handles {
52        for id in h.join().unwrap() {
53            all.insert(id);
54        }
55    }
56    println!("expected     = {}", 8 * 2000);
57    println!("unique seen  = {}", all.len());
58    println!("no duplicates= {}", all.len() == 8 * 2000);
59
60    println!("\n== Worker ID clamping ==");
61    let clamped = Snowflake::new(0xFFFF);
62    println!(
63        "constructor input 0xFFFF -> worker_id() = {}",
64        clamped.worker_id()
65    );
66    println!("(10-bit max = {})", 0x3FF);
67}
Source

pub const fn with_epoch(worker_id: u16, epoch_ms: u64) -> Self

Build a new generator with a custom epoch (milliseconds since the UNIX epoch).

§Example
use id_forge::snowflake::Snowflake;

// Twitter's original Snowflake epoch.
let gen = Snowflake::with_epoch(1, 1_288_834_974_657);
assert_eq!(gen.epoch_ms(), 1_288_834_974_657);
Examples found in repository?
examples/snowflake_distributed.rs (line 33)
18fn main() {
19    println!("== Default epoch (2026-01-01) ==");
20    let gen = Snowflake::new(7);
21    let id = gen.next_id();
22    let (ts_offset, worker, seq) = Snowflake::parts(id);
23    let wall_ms = ts_offset + gen.epoch_ms();
24    println!("id           = {id}");
25    println!("worker       = {worker}");
26    println!("seq          = {seq}");
27    println!("ts_offset_ms = {ts_offset}");
28    println!("wall_ms      = {wall_ms}");
29    println!("default epoch = {DEFAULT_EPOCH_MS}");
30
31    println!("\n== Twitter's original 2010 epoch ==");
32    let twitter_epoch_ms = 1_288_834_974_657;
33    let tw = Snowflake::with_epoch(9, twitter_epoch_ms);
34    let tw_id = tw.next_id();
35    let (tw_ts, tw_worker, _) = Snowflake::parts(tw_id);
36    println!("id           = {tw_id}");
37    println!("worker       = {tw_worker}");
38    println!("ts_offset_ms = {tw_ts}");
39    println!("wall_ms      = {}", tw_ts + tw.epoch_ms());
40
41    println!("\n== Multi-thread contention (8 threads x 2000 IDs) ==");
42    let gen = Arc::new(Snowflake::new(3));
43    let handles: Vec<_> = (0..8)
44        .map(|_| {
45            let g = Arc::clone(&gen);
46            thread::spawn(move || (0..2000).map(|_| g.next_id()).collect::<Vec<_>>())
47        })
48        .collect();
49
50    let mut all = HashSet::new();
51    for h in handles {
52        for id in h.join().unwrap() {
53            all.insert(id);
54        }
55    }
56    println!("expected     = {}", 8 * 2000);
57    println!("unique seen  = {}", all.len());
58    println!("no duplicates= {}", all.len() == 8 * 2000);
59
60    println!("\n== Worker ID clamping ==");
61    let clamped = Snowflake::new(0xFFFF);
62    println!(
63        "constructor input 0xFFFF -> worker_id() = {}",
64        clamped.worker_id()
65    );
66    println!("(10-bit max = {})", 0x3FF);
67}
Source

pub const fn worker_id(&self) -> u16

The worker ID this generator was built with, clamped to 10 bits.

§Example
use id_forge::snowflake::Snowflake;

assert_eq!(Snowflake::new(42).worker_id(), 42);
assert_eq!(Snowflake::new(0xffff).worker_id(), 0x3ff);  // clamped
Examples found in repository?
examples/snowflake_distributed.rs (line 64)
18fn main() {
19    println!("== Default epoch (2026-01-01) ==");
20    let gen = Snowflake::new(7);
21    let id = gen.next_id();
22    let (ts_offset, worker, seq) = Snowflake::parts(id);
23    let wall_ms = ts_offset + gen.epoch_ms();
24    println!("id           = {id}");
25    println!("worker       = {worker}");
26    println!("seq          = {seq}");
27    println!("ts_offset_ms = {ts_offset}");
28    println!("wall_ms      = {wall_ms}");
29    println!("default epoch = {DEFAULT_EPOCH_MS}");
30
31    println!("\n== Twitter's original 2010 epoch ==");
32    let twitter_epoch_ms = 1_288_834_974_657;
33    let tw = Snowflake::with_epoch(9, twitter_epoch_ms);
34    let tw_id = tw.next_id();
35    let (tw_ts, tw_worker, _) = Snowflake::parts(tw_id);
36    println!("id           = {tw_id}");
37    println!("worker       = {tw_worker}");
38    println!("ts_offset_ms = {tw_ts}");
39    println!("wall_ms      = {}", tw_ts + tw.epoch_ms());
40
41    println!("\n== Multi-thread contention (8 threads x 2000 IDs) ==");
42    let gen = Arc::new(Snowflake::new(3));
43    let handles: Vec<_> = (0..8)
44        .map(|_| {
45            let g = Arc::clone(&gen);
46            thread::spawn(move || (0..2000).map(|_| g.next_id()).collect::<Vec<_>>())
47        })
48        .collect();
49
50    let mut all = HashSet::new();
51    for h in handles {
52        for id in h.join().unwrap() {
53            all.insert(id);
54        }
55    }
56    println!("expected     = {}", 8 * 2000);
57    println!("unique seen  = {}", all.len());
58    println!("no duplicates= {}", all.len() == 8 * 2000);
59
60    println!("\n== Worker ID clamping ==");
61    let clamped = Snowflake::new(0xFFFF);
62    println!(
63        "constructor input 0xFFFF -> worker_id() = {}",
64        clamped.worker_id()
65    );
66    println!("(10-bit max = {})", 0x3FF);
67}
Source

pub const fn epoch_ms(&self) -> u64

The epoch this generator subtracts from the wall clock.

§Example
use id_forge::snowflake::{Snowflake, DEFAULT_EPOCH_MS};

assert_eq!(Snowflake::new(1).epoch_ms(), DEFAULT_EPOCH_MS);
Examples found in repository?
examples/basic.rs (line 23)
7fn main() {
8    let v4 = Uuid::v4();
9    println!("UUID v4:    {v4} (version={})", v4.version());
10    println!("UUID v7:    {}", Uuid::v7());
11    println!("UUID nil:   {}", Uuid::nil());
12
13    let a = Ulid::new();
14    let b = Ulid::new();
15    println!("ULID a:     {a}");
16    println!("ULID b:     {b} (monotonic: {})", b > a);
17
18    let gen = Snowflake::new(1);
19    let sf = gen.next_id();
20    let (ts_offset, worker, seq) = Snowflake::parts(sf);
21    println!(
22        "Snowflake:  {sf}  (ts+epoch={}, worker={worker}, seq={seq})",
23        ts_offset + gen.epoch_ms()
24    );
25
26    println!("NanoID 21:  {}", nanoid::generate());
27    println!("NanoID 8:   {}", nanoid::with_length(8));
28
29    assert_eq!(v4, Uuid::parse_str(&v4.to_string()).unwrap());
30    assert_eq!(a, Ulid::parse_str(&a.to_string()).unwrap());
31}
More examples
Hide additional examples
examples/snowflake_distributed.rs (line 23)
18fn main() {
19    println!("== Default epoch (2026-01-01) ==");
20    let gen = Snowflake::new(7);
21    let id = gen.next_id();
22    let (ts_offset, worker, seq) = Snowflake::parts(id);
23    let wall_ms = ts_offset + gen.epoch_ms();
24    println!("id           = {id}");
25    println!("worker       = {worker}");
26    println!("seq          = {seq}");
27    println!("ts_offset_ms = {ts_offset}");
28    println!("wall_ms      = {wall_ms}");
29    println!("default epoch = {DEFAULT_EPOCH_MS}");
30
31    println!("\n== Twitter's original 2010 epoch ==");
32    let twitter_epoch_ms = 1_288_834_974_657;
33    let tw = Snowflake::with_epoch(9, twitter_epoch_ms);
34    let tw_id = tw.next_id();
35    let (tw_ts, tw_worker, _) = Snowflake::parts(tw_id);
36    println!("id           = {tw_id}");
37    println!("worker       = {tw_worker}");
38    println!("ts_offset_ms = {tw_ts}");
39    println!("wall_ms      = {}", tw_ts + tw.epoch_ms());
40
41    println!("\n== Multi-thread contention (8 threads x 2000 IDs) ==");
42    let gen = Arc::new(Snowflake::new(3));
43    let handles: Vec<_> = (0..8)
44        .map(|_| {
45            let g = Arc::clone(&gen);
46            thread::spawn(move || (0..2000).map(|_| g.next_id()).collect::<Vec<_>>())
47        })
48        .collect();
49
50    let mut all = HashSet::new();
51    for h in handles {
52        for id in h.join().unwrap() {
53            all.insert(id);
54        }
55    }
56    println!("expected     = {}", 8 * 2000);
57    println!("unique seen  = {}", all.len());
58    println!("no duplicates= {}", all.len() == 8 * 2000);
59
60    println!("\n== Worker ID clamping ==");
61    let clamped = Snowflake::new(0xFFFF);
62    println!(
63        "constructor input 0xFFFF -> worker_id() = {}",
64        clamped.worker_id()
65    );
66    println!("(10-bit max = {})", 0x3FF);
67}
Source

pub fn try_next_id(&self) -> Result<u64, ClockSkew>

Generate the next ID, returning Err if the wall clock has moved backward since the previous call.

When 4096 IDs have been issued in the same millisecond, this method blocks in a microsecond sleep loop until the wall clock advances. It does not spin on a busy loop.

§Example
use id_forge::snowflake::Snowflake;

let gen = Snowflake::new(1);
let id = gen.try_next_id().expect("clock should not run backward");
assert!(id > 0);
Examples found in repository?
examples/snowflake_clock_skew.rs (line 25)
21fn main() {
22    let gen = Snowflake::new(1);
23
24    println!("== Normal path ==");
25    match gen.try_next_id() {
26        Ok(id) => println!("ok: id = {id}"),
27        Err(e) => println!("err: {e}"),
28    }
29
30    println!("\n== Recovering from a transient skew ==");
31    // Real services will see this when an NTP correction nudges the
32    // clock backward by a millisecond or two. The recommended
33    // strategy is: short pause, then retry. After at most ~1ms the
34    // wall clock is ahead of `last_ms` again and try_next_id
35    // returns Ok.
36    let mut attempts = 0usize;
37    let id = loop {
38        attempts += 1;
39        match gen.try_next_id() {
40            Ok(id) => break id,
41            Err(ClockSkew { last_ms, now_ms }) => {
42                // Backoff proportional to how far we regressed.
43                let drift = last_ms.saturating_sub(now_ms);
44                eprintln!("skew detected, drift = {drift} ms; backing off");
45                std::thread::sleep(Duration::from_millis(drift.max(1) + 1));
46                if attempts > 16 {
47                    panic!("clock failed to recover after {attempts} attempts");
48                }
49            }
50        }
51    };
52    println!("recovered    = {id} after {attempts} attempt(s)");
53
54    println!("\n== Burst rate ==");
55    // The CAS state machine handles contention without locks. A
56    // single-thread tight loop here is the uncontended path.
57    let start = std::time::Instant::now();
58    let burst = 100_000;
59    for _ in 0..burst {
60        let _ = gen.next_id();
61    }
62    let elapsed = start.elapsed();
63    println!(
64        "{burst} IDs in {elapsed:?} ({:.0} ns/op)",
65        elapsed.as_nanos() as f64 / burst as f64
66    );
67}
Source

pub fn next_id(&self) -> u64

Generate the next ID. Panics if the wall clock has moved backward since the previous call.

Use Snowflake::try_next_id when callers need to recover from clock skew (e.g. to surface it as a service-level error rather than crash the process).

§Panics

Panics with a ClockSkew description if the wall clock has regressed below the most recently issued ID’s timestamp.

§Example
use id_forge::snowflake::Snowflake;

let gen = Snowflake::new(1);
let id = gen.next_id();
assert!(id > 0);
Examples found in repository?
examples/bench.rs (line 43)
33fn main() {
34    println!("id-forge throughput (single thread, release build)");
35    println!("---------------------------------------------------");
36
37    let iters = 1_000_000;
38    bench("Uuid::v4", iters, Uuid::v4);
39    bench("Uuid::v7", iters, Uuid::v7);
40    bench("Ulid::new", iters, Ulid::new);
41
42    let sf = Snowflake::new(1);
43    bench("Snowflake::next_id", iters, || sf.next_id());
44
45    bench("nanoid::generate", iters / 5, nanoid::generate);
46    bench("nanoid::with_length(8)", iters / 5, || {
47        nanoid::with_length(8)
48    });
49    bench("nanoid::custom(16, hex)", iters / 5, || {
50        nanoid::custom(16, b"0123456789abcdef")
51    });
52    bench("nanoid::custom(21, 17-char)", iters / 5, || {
53        nanoid::custom(21, b"ABCDEFGHIJKLMNOPQ")
54    });
55}
More examples
Hide additional examples
examples/basic.rs (line 19)
7fn main() {
8    let v4 = Uuid::v4();
9    println!("UUID v4:    {v4} (version={})", v4.version());
10    println!("UUID v7:    {}", Uuid::v7());
11    println!("UUID nil:   {}", Uuid::nil());
12
13    let a = Ulid::new();
14    let b = Ulid::new();
15    println!("ULID a:     {a}");
16    println!("ULID b:     {b} (monotonic: {})", b > a);
17
18    let gen = Snowflake::new(1);
19    let sf = gen.next_id();
20    let (ts_offset, worker, seq) = Snowflake::parts(sf);
21    println!(
22        "Snowflake:  {sf}  (ts+epoch={}, worker={worker}, seq={seq})",
23        ts_offset + gen.epoch_ms()
24    );
25
26    println!("NanoID 21:  {}", nanoid::generate());
27    println!("NanoID 8:   {}", nanoid::with_length(8));
28
29    assert_eq!(v4, Uuid::parse_str(&v4.to_string()).unwrap());
30    assert_eq!(a, Ulid::parse_str(&a.to_string()).unwrap());
31}
examples/snowflake_clock_skew.rs (line 60)
21fn main() {
22    let gen = Snowflake::new(1);
23
24    println!("== Normal path ==");
25    match gen.try_next_id() {
26        Ok(id) => println!("ok: id = {id}"),
27        Err(e) => println!("err: {e}"),
28    }
29
30    println!("\n== Recovering from a transient skew ==");
31    // Real services will see this when an NTP correction nudges the
32    // clock backward by a millisecond or two. The recommended
33    // strategy is: short pause, then retry. After at most ~1ms the
34    // wall clock is ahead of `last_ms` again and try_next_id
35    // returns Ok.
36    let mut attempts = 0usize;
37    let id = loop {
38        attempts += 1;
39        match gen.try_next_id() {
40            Ok(id) => break id,
41            Err(ClockSkew { last_ms, now_ms }) => {
42                // Backoff proportional to how far we regressed.
43                let drift = last_ms.saturating_sub(now_ms);
44                eprintln!("skew detected, drift = {drift} ms; backing off");
45                std::thread::sleep(Duration::from_millis(drift.max(1) + 1));
46                if attempts > 16 {
47                    panic!("clock failed to recover after {attempts} attempts");
48                }
49            }
50        }
51    };
52    println!("recovered    = {id} after {attempts} attempt(s)");
53
54    println!("\n== Burst rate ==");
55    // The CAS state machine handles contention without locks. A
56    // single-thread tight loop here is the uncontended path.
57    let start = std::time::Instant::now();
58    let burst = 100_000;
59    for _ in 0..burst {
60        let _ = gen.next_id();
61    }
62    let elapsed = start.elapsed();
63    println!(
64        "{burst} IDs in {elapsed:?} ({:.0} ns/op)",
65        elapsed.as_nanos() as f64 / burst as f64
66    );
67}
examples/snowflake_distributed.rs (line 21)
18fn main() {
19    println!("== Default epoch (2026-01-01) ==");
20    let gen = Snowflake::new(7);
21    let id = gen.next_id();
22    let (ts_offset, worker, seq) = Snowflake::parts(id);
23    let wall_ms = ts_offset + gen.epoch_ms();
24    println!("id           = {id}");
25    println!("worker       = {worker}");
26    println!("seq          = {seq}");
27    println!("ts_offset_ms = {ts_offset}");
28    println!("wall_ms      = {wall_ms}");
29    println!("default epoch = {DEFAULT_EPOCH_MS}");
30
31    println!("\n== Twitter's original 2010 epoch ==");
32    let twitter_epoch_ms = 1_288_834_974_657;
33    let tw = Snowflake::with_epoch(9, twitter_epoch_ms);
34    let tw_id = tw.next_id();
35    let (tw_ts, tw_worker, _) = Snowflake::parts(tw_id);
36    println!("id           = {tw_id}");
37    println!("worker       = {tw_worker}");
38    println!("ts_offset_ms = {tw_ts}");
39    println!("wall_ms      = {}", tw_ts + tw.epoch_ms());
40
41    println!("\n== Multi-thread contention (8 threads x 2000 IDs) ==");
42    let gen = Arc::new(Snowflake::new(3));
43    let handles: Vec<_> = (0..8)
44        .map(|_| {
45            let g = Arc::clone(&gen);
46            thread::spawn(move || (0..2000).map(|_| g.next_id()).collect::<Vec<_>>())
47        })
48        .collect();
49
50    let mut all = HashSet::new();
51    for h in handles {
52        for id in h.join().unwrap() {
53            all.insert(id);
54        }
55    }
56    println!("expected     = {}", 8 * 2000);
57    println!("unique seen  = {}", all.len());
58    println!("no duplicates= {}", all.len() == 8 * 2000);
59
60    println!("\n== Worker ID clamping ==");
61    let clamped = Snowflake::new(0xFFFF);
62    println!(
63        "constructor input 0xFFFF -> worker_id() = {}",
64        clamped.worker_id()
65    );
66    println!("(10-bit max = {})", 0x3FF);
67}
Source

pub const fn parts(id: u64) -> (u64, u16, u16)

Decompose an ID minted by any Snowflake generator into its (timestamp_offset_ms, worker_id, sequence) parts.

The first element is the millisecond offset from whatever epoch the originating generator was built with. To recover the wall-clock millisecond, add the generator’s epoch_ms.

§Example
use id_forge::snowflake::Snowflake;

let gen = Snowflake::new(7);
let id = gen.next_id();
let (ts_offset, worker, seq) = Snowflake::parts(id);
assert_eq!(worker, 7);
assert!(seq <= 4095);
let wall_ms = ts_offset + gen.epoch_ms();
assert!(wall_ms > gen.epoch_ms());
Examples found in repository?
examples/basic.rs (line 20)
7fn main() {
8    let v4 = Uuid::v4();
9    println!("UUID v4:    {v4} (version={})", v4.version());
10    println!("UUID v7:    {}", Uuid::v7());
11    println!("UUID nil:   {}", Uuid::nil());
12
13    let a = Ulid::new();
14    let b = Ulid::new();
15    println!("ULID a:     {a}");
16    println!("ULID b:     {b} (monotonic: {})", b > a);
17
18    let gen = Snowflake::new(1);
19    let sf = gen.next_id();
20    let (ts_offset, worker, seq) = Snowflake::parts(sf);
21    println!(
22        "Snowflake:  {sf}  (ts+epoch={}, worker={worker}, seq={seq})",
23        ts_offset + gen.epoch_ms()
24    );
25
26    println!("NanoID 21:  {}", nanoid::generate());
27    println!("NanoID 8:   {}", nanoid::with_length(8));
28
29    assert_eq!(v4, Uuid::parse_str(&v4.to_string()).unwrap());
30    assert_eq!(a, Ulid::parse_str(&a.to_string()).unwrap());
31}
More examples
Hide additional examples
examples/snowflake_distributed.rs (line 22)
18fn main() {
19    println!("== Default epoch (2026-01-01) ==");
20    let gen = Snowflake::new(7);
21    let id = gen.next_id();
22    let (ts_offset, worker, seq) = Snowflake::parts(id);
23    let wall_ms = ts_offset + gen.epoch_ms();
24    println!("id           = {id}");
25    println!("worker       = {worker}");
26    println!("seq          = {seq}");
27    println!("ts_offset_ms = {ts_offset}");
28    println!("wall_ms      = {wall_ms}");
29    println!("default epoch = {DEFAULT_EPOCH_MS}");
30
31    println!("\n== Twitter's original 2010 epoch ==");
32    let twitter_epoch_ms = 1_288_834_974_657;
33    let tw = Snowflake::with_epoch(9, twitter_epoch_ms);
34    let tw_id = tw.next_id();
35    let (tw_ts, tw_worker, _) = Snowflake::parts(tw_id);
36    println!("id           = {tw_id}");
37    println!("worker       = {tw_worker}");
38    println!("ts_offset_ms = {tw_ts}");
39    println!("wall_ms      = {}", tw_ts + tw.epoch_ms());
40
41    println!("\n== Multi-thread contention (8 threads x 2000 IDs) ==");
42    let gen = Arc::new(Snowflake::new(3));
43    let handles: Vec<_> = (0..8)
44        .map(|_| {
45            let g = Arc::clone(&gen);
46            thread::spawn(move || (0..2000).map(|_| g.next_id()).collect::<Vec<_>>())
47        })
48        .collect();
49
50    let mut all = HashSet::new();
51    for h in handles {
52        for id in h.join().unwrap() {
53            all.insert(id);
54        }
55    }
56    println!("expected     = {}", 8 * 2000);
57    println!("unique seen  = {}", all.len());
58    println!("no duplicates= {}", all.len() == 8 * 2000);
59
60    println!("\n== Worker ID clamping ==");
61    let clamped = Snowflake::new(0xFFFF);
62    println!(
63        "constructor input 0xFFFF -> worker_id() = {}",
64        clamped.worker_id()
65    );
66    println!("(10-bit max = {})", 0x3FF);
67}

Trait Implementations§

Source§

impl Debug for Snowflake

Source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

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> 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, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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.