

[](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, cryptographically-sound IDs 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.
---
## 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`
Uses [`std::collections::hash_map::DefaultHasher`](https://doc.rust-lang.org/std/collections/hash_map/struct.DefaultHasher.html)
(SipHash 1-3). IDs are `u64` values. Faster than `crypto_hash`, but **not**
cryptographically secure — suitable for non-security-sensitive use cases.
---
## Feature flags
| `all` | ✅ | Enables both `crypto` and `rust` |
| `crypto` | ✅ | Enables `crypto_hash` module (requires `sha3` dep) |
| `rust` | ✅ | Enables `rust_hash` module |
To use only one module, disable default features in `Cargo.toml`:
```toml
# Only the rust hasher — no sha3 dependency
ids_service = { version = "2.0.2", default-features = false, features = ["rust"] }
# Only the crypto hasher
ids_service = { version = "2.0.2", default-features = false, 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
}
```
### Rust hasher (`rust_hash`)
```rust
use ids_service::rust_hash::IdsService;
use ids_service::common::{Service, Uids};
fn main() {
// Cache size = 200 000, thread count = number of logical CPUs
let mut ids = IdsService::new(200_000, None);
ids.start();
let _ = ids.filled_at_percent_event(10).recv();
println!("id: {}", ids.get_id());
println!("from cache: {}", ids.get_id_from_cache().expect("cache non-empty"));
println!("cache len: {}", ids.get_cache_len());
ids.stop();
}
```
### Standalone (no service, no cache)
```rust
use ids_service::rust_hash::create_id;
fn main() {
println!("{}", create_id()); // u64
}
```
---
## Performance
Benchmarks run with [Criterion.rs](https://bheisler.github.io/criterion.rs/book/) on an
**AMD Ryzen AI 7 350** — `cargo bench`.
### Results
| `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 | — |
| `rust_hash/standalone/create_id` | ~42.8 ns | ~23.3 Melem/s |
| `rust_hash/service/get_id` | ~118–157 ns | ~6.4–8.5 Melem/s |
> **`crypto_hash` cache hit ≈ 149–170 ns — 2–6× faster than standalone SHA3-256/SHA3-512
> generation (Mutex::lock + VecDeque::pop_front vs. full hash computation).**
>
> **`rust_hash` cache hit ≈ 118–157 ns — service overhead exceeds standalone (~43 ns);
> use `create_id()` directly when maximum throughput is the priority.**
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
# Rust hasher examples
cargo run --example quickstart_rh
cargo run --example quickstart2_rh
cargo run --example examples_rh
cargo run --example iterator_example_rh
# Generate 10 million IDs and measure throughput
cargo run --release --example ten_million
cargo run --release --example ten_million_rh
```
---
## Running tests
```bash
# All unit and doc tests
cargo test
# With a specific feature set
cargo test --no-default-features --features crypto
cargo test --no-default-features --features rust
```
---
## Platforms
Compiled and tested on:
1. x86_64 GNU/Linux (primary development + CI)
2. macOS (Apple Silicon M1)
---
## License
MIT — see [LICENSE](LICENSE).