#uuid #hash #id

ids_service

Library that allows to generate unique Ids

10 stable releases

Uses new Rust 2024

2.1.4 Jun 7, 2026
2.1.1 Mar 2, 2026
1.3.7 Jan 3, 2023
1.3.4 Jan 1, 2022
0.1.6 Jan 27, 2019

#224 in Algorithms


Used in dmslite

MIT license

57KB
840 lines

Licence Version dependency status Download pipeline docs.rs

ids_service

A Rust library for generating unique, random IDs derived from a cryptographically secure random source, using a pre-filled, multi-threaded cache. Background worker threads keep the cache full so that callers receive a pre-computed ID instantly without blocking.

If the cache is temporarily exhausted (burst traffic), an ID is generated on the fly — no error, no panic, just a small latency spike.

Generated IDs are purely random and carry no temporal information, making them non-sortable by time. This is a deliberate trade-off: unlike ULID or UUID v7, which embed a timestamp to allow chronological ordering, this library prioritises unpredictability over sortability. If time-based ordering is a requirement, consider using a dedicated crate such as uuid7 or uuid with the v7 feature.


How it works

  ┌──────────────────────────────────────────────────────┐
  │                    IdsService                        │
  │                                                      │
  │  ┌──────────┐   push    ┌─────────────────────────┐ │
  │  │ Worker 0 │ ────────► │                         │ │
  │  ├──────────┤           │  Arc<Mutex<VecDeque>>   │ │  get_id()
  │  │ Worker 1 │ ────────► │       (cache)           │ ├──────────► caller
  │  ├──────────┤           │                         │ │
  │  │ Worker N │ ────────► │  size = cache_size      │ │
  │  └──────────┘           └─────────────────────────┘ │
  │                                                      │
  │  Each ID = hash( random_bytes || timestamp_ns )      │
  └──────────────────────────────────────────────────────┘

Each ID is derived from:

  • A random byte block (size = 2 × hash output length — see Birthday problem)
  • The current timestamp in nanoseconds since the Unix epoch

Modules

crypto_hash

Uses one of the SHA-3 family algorithms from the sha3 crate:

Mode Output Random block
Sha3Mode::Sha3_224 28 bytes 56 bytes
Sha3Mode::Sha3_256 32 bytes 64 bytes
Sha3Mode::Sha3_384 48 bytes 96 bytes
Sha3Mode::Sha3_512 64 bytes 128 bytes

IDs can be encoded as:

Method Output
.as_hex() Lowercase hexadecimal String
.as_base64() Standard Base64 String
.as_base64_url() URL-safe Base64 String
.as_base32() Base32 String
.as_json() JSON array of byte values

rust_hash ⚠️ Deprecated

Deprecated since 2.1.0. Use the crypto feature and crypto_hash module instead, or consider the uuid crate.


Feature flags

Flag Default Description
crypto Enables crypto_hash module (requires sha3 dep)
rust Deprecated. Enables rust_hash module

To use only the crypto module:

ids_service = { version = "2.1.2", features = ["crypto"] }

Quick Start

Cryptographic hash (crypto_hash)

use ids_service::crypto_hash::{IdsService, Sha3Mode};
use ids_service::common::{Encode, Service, Uids};

fn main() {
    // Cache size = 100 000, SHA3-256, thread count = number of logical CPUs
    let mut ids = IdsService::new(100_000, Sha3Mode::Sha3_256, None);
    ids.start();

    // Optional: block until the cache is at least 10 % full
    let _ = ids.filled_at_percent_event(10).recv();

    println!("hex:    {}", ids.get_id().as_hex());
    println!("base64: {}", ids.get_id().as_base64());
    println!("base32: {}", ids.get_id().as_base32());

    // Returns None when the cache is empty instead of generating on the fly
    if let Some(id) = ids.get_id_from_cache() {
        println!("from cache: {}", id.as_hex());
    }

    println!("cache len: {}", ids.get_cache_len());

    // Graceful shutdown — joins worker threads
    ids.stop();
}

Or use the default configuration (SHA3-256, 100 000 items, CPU-count threads):

use ids_service::crypto_hash::IdsService;
use ids_service::common::{Encode, Service, Uids};

fn main() {
    let mut ids = IdsService::default();
    ids.start();
    let _ = ids.filled_event().recv(); // wait for full cache
    println!("{}", ids.get_id().as_hex());
    ids.stop();
}

Iterator interface

IdsService implements Iterator, yielding one ID per call:

use ids_service::crypto_hash::{IdsService, Sha3Mode};
use ids_service::common::{Encode, Service};

fn main() {
    let mut ids = IdsService::new(10_000, Sha3Mode::Sha3_512, None);
    ids.start();

    for id in ids.by_ref().take(5) {
        println!("{}", id.as_hex());
    }

    ids.stop();
}

Standalone (no service, no cache)

use ids_service::crypto_hash::{create_id_as_sha256, create_id_as_sha512};

fn main() {
    println!("{}", create_id_as_sha256()); // hex-encoded SHA3-256
    println!("{}", create_id_as_sha512()); // hex-encoded SHA3-512
}

Performance

Benchmarks run with Criterion.rs on an AMD Ryzen AI 7 350cargo bench.

Benchmark Median time Throughput
crypto_hash/standalone/sha256 ~379 ns ~2.64 Melem/s
crypto_hash/standalone/sha512 ~926 ns ~1.08 Melem/s
crypto_hash/service/get_id/Sha3_256 ~149–170 ns ~5.9–6.8 Melem/s
crypto_hash/service/get_id/Sha3_512 ~102–120 ns ~8.4–9.8 Melem/s
crypto_hash/encoding/as_hex ~24.9 ns
crypto_hash/encoding/as_base64 ~28.4 ns
crypto_hash/encoding/as_base32 ~29.4 ns

Cache hit ≈ 149–170 ns — 2–6× faster than standalone SHA3-256/SHA3-512 generation.

Run the full benchmark suite:

cargo bench --bench throughput

Results are saved as HTML reports in target/criterion/.


Examples

# Cryptographic hasher examples
cargo run --example quickstart
cargo run --example quickstart2
cargo run --example examples
cargo run --example iterator_example

# Generate 10 million IDs and measure throughput
cargo run --release --example ten_million

Running tests

# All unit and doc tests
cargo test

# With a specific feature set
cargo test --no-default-features --features crypto

Platforms

Compiled and tested on:

  1. x86_64 GNU/Linux (primary development + CI)
  2. macOS (Apple Silicon M1)

License

MIT — see LICENSE. ID

Dependencies

~530–760KB
~12K SLoC