# Qubit ID (`rs-id`)
[](https://github.com/qubit-ltd/rs-id/actions/workflows/ci.yml)
[](https://qubit-ltd.github.io/rs-id/coverage/)
[](https://crates.io/crates/qubit-id)
[](https://docs.rs/qubit-id)
[](https://www.rust-lang.org)
[](LICENSE)
[](README.zh_CN.md)
Documentation: [API Reference](https://docs.rs/qubit-id)
`qubit-id` provides ID generation utilities for Rust services.
It includes one common `IdGenerator<T>` trait plus generators for
database-friendly Snowflake IDs, Sonyflake-style IDs, and fast UUID-like random
identifiers.
## Why Use It
Use `qubit-id` when you need:
- Qubit Snowflake IDs with fixed high-bit mode and precision headers
- classic Snowflake IDs with a compact 64-bit numeric representation
- Sonyflake-style IDs with longer runtime under small sequence pressure
- fast UUID-like random strings
- one trait-based API that can return typed IDs and string representations
## Installation
```toml
[dependencies]
qubit-id = "0.2"
```
## Quick Start
```rust
use qubit_id::{IdGenerator, MicaUuidLikeGenerator, QubitSnowflakeGenerator};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let snowflake = QubitSnowflakeGenerator::new(1)?;
let id: u64 = snowflake.next_id()?;
let id_text = snowflake.next_string()?;
let uuid_like = MicaUuidLikeGenerator::new();
let uuid_like_value: u128 = uuid_like.next_id()?;
let uuid_like_text = uuid_like.next_string()?;
println!("{id} {id_text} {uuid_like_value} {uuid_like_text}");
Ok(())
}
```
## Core API At A Glance
| `IdGenerator<T>` | Common trait for typed ID generation and string formatting. |
| `QubitSnowflakeGenerator` | Qubit fixed-header Snowflake generator. |
| `QubitSnowflakeBuilder` | Builds and inspects Qubit Snowflake bit layouts. |
| `SnowflakeGenerator` | Classic 41-bit time, 10-bit node, 12-bit sequence Snowflake generator. |
| `SonyflakeGenerator` | Sonyflake-style generator with configurable sequence and machine bits. |
| `MicaUuidLikeGenerator` | Mica-style random 128-bit UUID-like generator. |
| `fast_uuid_like` | Generates canonical lowercase UUID-like text. |
| `fast_simple_uuid_like` | Generates compact lowercase 32-hex UUID-like text. |
## Generator Examples
### QubitSnowflakeGenerator
Use `QubitSnowflakeGenerator` for the Qubit fixed-header Snowflake layout. The
default constructor uses sequential mode, second precision, and the default
Qubit epoch.
```rust
use qubit_id::{IdGenerator, QubitSnowflakeGenerator};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// The argument is the 9-bit host ID encoded into generated IDs.
// It must be in the range 0..=511.
let generator = QubitSnowflakeGenerator::new(42)?;
let id = generator.next_id()?;
let id_text = generator.next_string()?;
let builder = generator.builder();
assert_eq!(builder.extract_host(id), 42);
println!("{id} {id_text}");
Ok(())
}
```
Configure the Qubit layout explicitly when you need spread mode or millisecond
precision.
```rust
use std::time::{Duration, UNIX_EPOCH};
use qubit_id::{
IdGenerator, IdMode, QubitSnowflakeGenerator, TimestampPrecision,
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let generator = QubitSnowflakeGenerator::with_options(
IdMode::Spread,
TimestampPrecision::Millisecond,
7,
UNIX_EPOCH + Duration::from_millis(1_543_708_800_000),
)?;
let id = generator.next_id()?;
let builder = generator.builder();
assert_eq!(builder.extract_mode(id), IdMode::Spread);
assert_eq!(builder.extract_precision(id), TimestampPrecision::Millisecond);
assert_eq!(builder.extract_host(id), 7);
Ok(())
}
```
### SnowflakeGenerator
Use `SnowflakeGenerator` when you need the classic 41-bit millisecond timestamp,
10-bit node, and 12-bit sequence layout.
```rust
use qubit_id::{IdGenerator, SnowflakeGenerator};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let generator = SnowflakeGenerator::new(3)?;
let id = generator.next_id()?;
assert_eq!(generator.extract_node_id(id), 3);
println!("{id}");
Ok(())
}
```
You can also compose and inspect deterministic IDs from known parts.
```rust
use qubit_id::SnowflakeGenerator;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let generator = SnowflakeGenerator::new(3)?;
let id = generator.compose(1_000, 5)?;
assert_eq!(generator.extract_timestamp(id), 1_000);
assert_eq!(generator.extract_node_id(id), 3);
assert_eq!(generator.extract_sequence(id), 5);
Ok(())
}
```
### SonyflakeGenerator
Use `SonyflakeGenerator` when a larger machine ID space matters more than
per-machine burst throughput.
```rust
use qubit_id::{IdGenerator, SonyflakeGenerator};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let generator = SonyflakeGenerator::new(65_535)?;
let id = generator.next_id()?;
assert_eq!(generator.extract_machine_id(id), 65_535);
println!("{id}");
Ok(())
}
```
For custom deployments, configure the sequence bits, machine bits, time unit,
and start time explicitly.
```rust
use std::time::{Duration, UNIX_EPOCH};
use qubit_id::{IdGenerator, SonyflakeGenerator};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let generator = SonyflakeGenerator::with_options(
15,
10,
14,
Duration::from_millis(1),
UNIX_EPOCH + Duration::from_secs(1_735_689_600),
)?;
let id = generator.next_id()?;
assert_eq!(generator.bits_sequence(), 10);
assert_eq!(generator.bits_machine(), 14);
assert_eq!(generator.extract_machine_id(id), 15);
Ok(())
}
```
### MicaUuidLikeGenerator And Helpers
Use `MicaUuidLikeGenerator` when you want a random 128-bit value with UUID-like
lowercase text formatting. Use the helper functions when you only need strings.
```rust
use qubit_id::{
IdGenerator, MicaUuidLikeGenerator, fast_simple_uuid_like, fast_uuid_like,
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let generator = MicaUuidLikeGenerator::new();
let value = generator.next_id()?;
let canonical = generator.format_id(&value);
let compact = MicaUuidLikeGenerator::format_simple_uuid_like(value);
let random_canonical = fast_uuid_like()?;
let random_compact = fast_simple_uuid_like()?;
println!("{canonical} {compact} {random_canonical} {random_compact}");
Ok(())
}
```
## Algorithm Notes
`QubitSnowflakeGenerator` is the default Snowflake-style generator for Qubit
Rust services. It uses a fixed high-bit header:
```text
[mode:1][precision:1][timestamp][host:9][sequence]
```
The field widths are:
| `mode` | 1 bit | Encodes the ID ordering mode: sequential or spread. |
| `precision` | 1 bit | Encodes timestamp precision: millisecond or second. |
| `timestamp` | 41 bits in millisecond precision; 31 bits in second precision | Number of elapsed time slices since the configured epoch. |
| `host` | 9 bits | Host identifier in `0..=511`. |
| `sequence` | 12 bits in millisecond precision; 22 bits in second precision | Incrementing sequence inside the same time slice. |
The fixed `mode` and `precision` positions make those header fields readable
without knowing the timestamp and sequence widths first.
This layout prioritizes a self-describing header, so the ID mode and precision
can be identified directly during parsing.
### Choosing A Snowflake Generator
| `QubitSnowflakeGenerator` | Encodes `mode` and `precision` in fixed high bits, so parsers can identify layout metadata directly; supports millisecond and second precision, with the default second precision providing a larger per-host sequence space; supports sequential and spread modes; tolerates small clock rollbacks by default. | Uses the Qubit fixed-header layout; the host field is 9 bits, allowing up to 512 host identifiers. |
| `SnowflakeGenerator` | Uses the classic 41-bit millisecond time, 10-bit node, and 12-bit sequence layout; simple and familiar when a traditional Snowflake shape is required. | Fixed layout with no encoded mode or precision; clock rollback returns an error immediately; no spread mode. |
| `SonyflakeGenerator` | Uses a 63-bit ID with 10 ms time units and a 16-bit machine field by default, which fits deployments that need more machine identifiers; sequence and machine bits are configurable. | The default 8-bit sequence per time slice has lower per-machine burst throughput than millisecond Snowflake layouts; 10 ms time units provide coarser ordering. |
For most new services, prefer `QubitSnowflakeGenerator`: it still produces a
compact `u64` numeric ID while keeping layout metadata in fixed high bits, which
makes parsing, debugging, and future evolution more direct. Choose
`SnowflakeGenerator` when the traditional 41/10/12 layout is required, and
choose `SonyflakeGenerator` when machine ID space matters more than per-machine
burst throughput.
### MicaUuidLikeGenerator
`MicaUuidLikeGenerator` is only a random number generator that mimics the
canonical UUID text shape. It uses 128 random bits and formats them as lowercase
UUID-like text. It does not rewrite RFC UUID version or variant bits, so it
should not be treated as a standards-compliant UUID v4 generator.
The UUID-like formatter follows Mica's fast UUID helper and
[`formatUnsignedLong`](https://github.com/lets-mica/mica/blob/master/mica-core/src/main/java/net/dreamlu/mica/core/utils/StringUtil.java#L348)
formatter from
[`StringUtil`](https://github.com/lets-mica/mica/blob/master/mica-core/src/main/java/net/dreamlu/mica/core/utils/StringUtil.java#L335).
Mica's UUID benchmark notes are available in the
[mica-jmh wiki](https://github.com/lets-mica/mica-jmh/wiki/uuid).
## Project Scope
- This crate focuses on local ID generation, not distributed node discovery.
- Clock rollback is handled by waiting within the configured tolerance and
returning an explicit error when the skew is too large.
- `QubitSnowflakeGenerator` uses its own fixed-header Snowflake layout.
- `SnowflakeGenerator` and `SonyflakeGenerator` are available for services that
intentionally choose those layouts.
## Contributing
Issues and pull requests are welcome.
Please keep contributions focused and easy to review:
- open an issue for bug reports, design questions, or larger feature proposals
- keep pull requests scoped to one behavior change, fix, or documentation update
- run `./ci-check.sh` before submitting changes
- include tests when changing runtime behavior
- update the README when public API behavior changes
By contributing to this project, you agree that your contribution will be
licensed under the same license as the project.
## License
Licensed under the [Apache License, Version 2.0](LICENSE).