Robust and Hassle-Free ULIDs (Universally Unique Lexicographically Sortable Identifiers)
mr-ulid
is designed with a focus on correctness and ease of use. It ensures that ULIDs generated are unique and strictly monotonically increasing.
By providing both Ulid
and ZeroableUlid
types, it serves different application needs, whether you require non-zero guarantees or need to handle zero ULIDs.
- Robust: Generates ULIDs that are unique and strictly monotonically increasing under all circumstances, including threads, no failing, and no overflowing random part. See below for Details.
- Hassle-Free: Simple API for easy usage. Customize entropy source when needed.
- Non-Zero ULIDs: Provides non-zero (
Ulid
) and zeroable (ZeroableUlid
) types. - Minimal Dependencies: Actually no dependencies required, only
rand
enabled by default as Rust lacks a built-in random number generator. - Optional Features: Supports
serde
for serialization and deserialization.
A notable guarantee of this crate is that a sufficient number of ULIDs can be generated at any time without failing or the random part overflowing.
The 80-bit random component of a ULID is slightly reduced by 1010 values, resulting in a negligible reduction in entropy of approximately 0.000000000001%. This ensures that at least 1010 ULIDs can be generated per millisecond, equating to 1013 ULIDs per second. Such capacity exceeds the capabilities of current systems by magnitudes.
Add mr-ulid
to your Cargo.toml
:
[dependencies]
mr-ulid = "1"
use mr_ulid::Ulid;
fn main() {
// Generate a ULID
let u = Ulid::generate();
// Print a ULID
println!("Generated ULID: {u}");
// Convert a ULID to a string
let s = ulid.to_string();
// Parse the string back into a ULID
let parsed: Ulid = s.parse().unwrap();
// Verify that the original and parsed ULIDs are the same
assert_eq!(u, parsed);
}
To enable serialization and deserialization, add serde
and serde_json
to your Cargo.toml
, and enable the serde
feature for mr-ulid
:
[dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = { version = "1" }
mr-ulid = { version = "1", features = ["serde"] }
use mr_ulid::Ulid;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct Example {
id: Ulid,
data: String,
}
fn main() {
let example = Example {
id: Ulid::generate(),
data: "Hello, ULID!".to_string(),
};
// Serialize to JSON
let json = serde_json::to_string(&example).unwrap();
println!("Serialized JSON: {json}");
// Deserialize back to struct
let deserialized: Example = serde_json::from_str(&json).unwrap();
// Verify that the original and deserialized structs are the same
assert_eq!(example, deserialized);
}
Contributions are welcome! Whether it's a bug fix, new feature, or improvement, your help is appreciated. Please feel free to open issues or submit pull requests on the GitHub repository.
This project is licensed under the MIT License.