Skip to main content

grain_id/
lib.rs

1//! Compact, human-readable unique IDs — grain-sized, yet enough for a lifetime.
2//!
3//! For a language agnostic specification of the grain-id format, see [SPECS.md](https://github.com/fluo10/grain-id/blob/main/SPECS.md)
4//!
5//! # Quick Start
6//! ```rust
7//! use grain_id::GrainId;
8//!
9//! let id = GrainId::random();
10//! println!("{}", id); // e.g. "123abcd"
11//! ```
12//!
13//! # Why grain-id?
14//!
15//! Traditional identifier systems face challenges in distributed environments:
16//!
17//! - **Sequential numbers** (like GitHub issue numbers) cause collisions in distributed systems
18//! - **UUIDs** are too long and not human-friendly
19//! - **Short hashes** (like Git commit hashes) lack standardization
20//!
21//! grain-id bridges the gap between human readability and technical requirements.
22//!
23//! # Installation
24//!
25//! Add this to your `Cargo.toml`:
26//! ```toml
27//! [dependencies]
28//! grain-id = "0.14.1"
29//!
30//! # With optional features
31//! grain-id = { version = "0.15.0", features = ["arbitrary", "serde", "rusqlite", "sea-orm", "prost", "schemars"] }
32//! ```
33//!
34//! ## For no_std Environments
35//!
36//! This crate support `no_std`.
37//! For `no_std` environment, you'll need to disable default features.
38//! ```toml
39//! [dependencies]
40//! grain-id = { version = "0.14.1", default-features = false }
41//! ```
42//!
43//! # Features
44//!
45//! - **Human-friendly**: Easy to read, type, and communicate
46//! - **Collision-resistant**: Sufficient entropy for personal distributed systems
47//! - **Compact**: Shorter than UUIDs while maintaining uniqueness
48//! - **Type-safe**: Rust implementation with strong typing
49//! - **Multiple integrations**: Support for serde, rusqlite, sea-orm, and protobuf
50//!
51//! ## Optional Feature Flags
52//!
53//! - `arbitrary`: `arbitrary::Arbitrary` support for fuzzing tests.
54//! - `digest`: Hash-based [`GrainId`] generation via [`digest::Digest`] trait.
55//! - `serde`: Serialization/deserialization support
56//! - `rusqlite`: SQLite database integration
57//! - `sea-orm`: SeaORM ORM integration
58//! - `prost`: Protocol Buffers support
59//! - `schemars`: JSON Schema support
60//!
61//! # Examples
62//! ```rust
63//! use grain_id::GrainId;
64//! # fn main() -> Result<(), grain_id::Error> {
65//! // Generate random grain-id
66//! let grain_id = GrainId::random();
67//!
68//! // e.g. `123abcd`
69//! println!("'{}'", grain_id);
70//!
71//! // Parse from string
72//! let valid_id: GrainId = "012atvw".parse()?;
73//!
74//! // When decoding from BASE32, ambiguous characters (1/l/I, 0/o, v/u) are treated as 1, 0 and v respectively, so they do not cause errors.
75//! let also_valid_id: GrainId = "ol2atuw".parse()?;
76//! assert_eq!(valid_id, also_valid_id);
77//!
78//! // Convert to/from integer
79//! let num: u64 = valid_id.into();
80//! let id_from_int: GrainId = num.try_into()?;
81//! assert_eq!(valid_id, id_from_int);
82//!
83//! // Lossy conversion from oversized int is allowed.
84//! let id_from_overflowed_int = GrainId::from_u64_lossy(GrainId::CAPACITY + num);
85//! assert_eq!(valid_id, id_from_overflowed_int);
86//!
87//! # Ok(())
88//! # }
89//! ```
90#![cfg_attr(not(feature = "std"), no_std)]
91#![cfg_attr(docsrs, feature(doc_cfg))]
92
93#[cfg(all(not(feature = "std"), not(test)))]
94#[macro_use]
95extern crate core as std;
96
97/// Provides constants and private functions about encoding/decoding alphabet.
98///
99/// This module implements encoding and decoding character based on [Crockford's Base32](https://www.crockford.com/base32.html) with following exceptions:
100///
101/// - The letter `u` (`U`) is decoded to 27, same as `v`.
102/// - Characters are separated by hyphens every three characters (triplet) during encoding.
103///   During decoding, hyphens may be omitted or replaced with underscores.
104pub mod alphabet;
105mod core;
106mod error;
107mod macros;
108
109#[cfg(feature = "std")]
110mod prefix;
111
112#[cfg(feature = "std")]
113mod std;
114
115#[cfg(feature = "arbitrary")]
116mod arbitrary;
117
118#[cfg(feature = "schemars")]
119mod schemars;
120
121#[cfg(feature = "digest")]
122mod digest;
123
124#[cfg(feature = "rand")]
125mod rand;
126
127#[cfg(feature = "serde")]
128mod serde;
129
130#[cfg(feature = "prost")]
131mod prost;
132
133#[cfg(feature = "rusqlite")]
134mod rusqlite;
135
136#[cfg(feature = "sea-orm")]
137mod sea_orm;
138
139pub use core::GrainId;
140pub use error::Error;
141#[cfg(feature = "std")]
142pub use prefix::GrainIdPrefix;
143/// Provides message types generated by prost-build.
144#[cfg(feature = "prost")]
145pub mod proto;
146
147/// Alias of [`proto::GrainId`]
148#[cfg(feature = "prost")]
149pub type GrainIdProto = proto::GrainId;
150
151/// Alias of [`proto::GrainIdPrefix`]
152#[cfg(all(feature = "prost", feature = "std"))]
153pub type GrainIdPrefixProto = proto::GrainIdPrefix;