ids_service 2.1.0

Library that allows to generate unique Ids.
Documentation
![Licence](https://img.shields.io/crates/l/ids_service)
![Version](https://img.shields.io/crates/v/ids_service)
[![dependency status](https://deps.rs/repo/gitlab/kurdy/ids_service/status.svg)](https://deps.rs/repo/gitlab/kurdy/ids_service)
![Download](https://img.shields.io/crates/d/ids_service)
[![pipeline](https://gitlab.com/kurdy/ids_service/badges/master/pipeline.svg)](https://gitlab.com/kurdy/ids_service)
[![docs.rs](https://img.shields.io/docsrs/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:

| 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`]https://crates.io/crates/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:

```toml
ids_service = { version = "2.1.0", 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`.

| 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:

```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).