ids_service 2.1.1

Library that allows to generate unique Ids.
Documentation

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.1", 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.