

[](https://deps.rs/repo/gitlab/kurdy/ids_service)

[](https://gitlab.com/kurdy/ids_service)
[](https://docs.rs/ids_service)
# 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](https://crates.io/crates/uuid7) or [uuid](https://crates.io/crates/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](https://en.m.wikipedia.org/wiki/Birthday_problem#Probability_table))
- The current timestamp in nanoseconds since the Unix epoch
---
## Modules
### `crypto_hash`
Uses one of the SHA-3 family algorithms from the [`sha3`](https://crates.io/crates/sha3) crate:
| `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:
| `.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`](https://crates.io/crates/uuid) crate.
---
## Feature flags
| `crypto` | ✅ | Enables `crypto_hash` module (requires `sha3` dep) |
| `rust` | ❌ | **Deprecated.** Enables `rust_hash` module |
To use only the crypto module:
```toml
ids_service = { version = "2.1.1", features = ["crypto"] }
```
---
## Quick Start
### Cryptographic hash (`crypto_hash`)
```rust
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):
```rust
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:
```rust
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)
```rust
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](https://bheisler.github.io/criterion.rs/book/) on an
**AMD Ryzen AI 7 350** — `cargo bench`.
| `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:
```bash
cargo bench --bench throughput
```
Results are saved as HTML reports in `target/criterion/`.
---
## Examples
```bash
# 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
```bash
# 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](LICENSE).