1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
//! A human-friendly identifier format based on 3-character blocks ("triplet").
//! This crate provides multiple fixed-length variants:
//!
//! - `Stid`: Single triplet ID (e.g. `123`)
//! - `Dtid`: Double Triplet ID (e.g. `456-789`)
//! - `Ttid`: Triple Triplet ID (e.g. `abc-def-ghj`)
//! - `Qtid`: Quadruple triplet ID (e.g. `kmn-pqr-stv-wxy`)
//!
//! For a language agnostic specification of the MTID format, see [SPECS.md](https://github.com/fluo10/mtid/blob/main/SPECS.md)
//!
//! # Quick Start
//!
//! ```
//! use mtid::Dtid;
//!
//! let id = Dtid::random();
//! println!("{}", id); // e.g. "1a2-b3c"
//! ```
//!
//! # Why MTID?
//!
//! Traditional identifier systems face challenges in distributed environments:
//!
//! - **Sequential numbers** (like GitHub issue numbers) cause collisions in distributed systems
//! - **UUIDs** are too long and not human-friendly
//! - **Short hashes** (like Git commit hashes) lack standardization
//!
//! MTID bridges the gap between human readability and technical requirements.
//!
//! # Which length should I use?
//!
//! - DTID(Double length triplet ID) is recommended for the personal data
//! because this is short enough to satisfy the Magic Number 7±2 principle and have enough range of value
//! (for the data entered manually by individuals (such as pocketbooks, journals, or activity logs)).
//! - STID(Single length triplet ID) is recommended if the data is expected to be so few that they can be counted.
//! - TTID(Triple length triplet ID) is recommended if it is expected that one or more data will be added every second.
//! - QTID(Quadruple length Triplet ID) is recommended if, the number of data could potentially become so large that it's impossible to predict
//! (for example, in a multi-user application where the IDs must be unique across users).
//!
//! # Installation
//!
//! Add this to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! mtid = "0.6"
//!
//! # With optional features
//! mtid = { version = "0.6", features = ["arbitrary", "serde", "rusqlite", "sea-orm", "prost"] }
//! ```
//!
//! ## For no_std Environments
//!
//! This crate support `no_std`.
//! For `no_std` environment, you'll need to disable default features.
//!
//! ```toml
//! [dependencies]
//! mtid = { version = "0.6", default-features = false }
//! ```
//!
//! # Features
//!
//! - **Human-friendly**: Easy to read, type, and communicate
//! - **Collision-resistant**: Sufficient entropy for distributed systems
//! - **Compact**: Shorter than UUIDs while maintaining uniqueness
//! - **Type-safe**: Rust implementation with strong typing
//! - **Multiple integrations**: Support for serde, rusqlite, sea-orm, and protobuf
//!
//! ## Optional Feature Flags
//!
//! - `arbitrary`: `arbitrary::Arbitrary` support for fuzzing tests.
//! - `serde`: Serialization/deserialization support
//! - `rusqlite`: SQLite database integration
//! - `sea-orm`: SeaORM ORM integration
//! - `prost`: Protocol Buffers support
//!
//! # Examples
//!
//! ```rust
//! use mtid::{Stid, Dtid, Ttid, Qtid};
//! # fn main() -> Result<(), mtid::Error> {
//! // Generate random MTID
//! let stid = Stid::random();
//! let dtid = Dtid::random();
//! let ttid = Ttid::random();
//! let qtid = Qtid::random();
//!
//! // '123', '456-789', 'abc-def-ghj', 'kmn-pqr-stv-wxy'
//! println!("'{}', '{}', '{}'. '{}'", stid, dtid, ttid, qtid);
//!
//! // Parse from string
//! let valid_id: Dtid = "012-tvw".parse()?;
//!
//! // The code without delimiter is valid.
//! let valid_id_without_delimiter: Dtid = "012tvw".parse()?;
//! assert_eq!(valid_id, valid_id_without_delimiter);
//!
//! // When decoding from BASE32, ambiguous characters (1/l/I, 0/o, v/u, -/_) are treated as 1, 0, v, and - respectively, so they do not cause errors.
//! let also_valid_id: Dtid = "ol2_tuw".parse()?;
//! assert_eq!(valid_id, also_valid_id);
//!
//! // Convert to/from integer
//! let num: u32 = valid_id.into();
//! let id_from_int: Dtid = num.try_into()?;
//! assert_eq!(valid_id, id_from_int);
//!
//! // Lossy conversion from oversized int is allowed.
//! let id_from_overflowed_int = Dtid::from_uint_lossy(Dtid::CAPACITY + num);
//! assert_eq!(valid_id, id_from_overflowed_int);
//!
//! # Ok(())
//! # }
//! ```
extern crate core as std;
/// Provides constants and private functions about encoding/decoding alphabet.
///
/// This module implements encoding and decoding character based on [Crockford's Base32](https://www.crockford.com/base32.html) with following exceptions:
///
/// - The letter `u` (`U`) is decoded to 27, same as `v`.
/// - Characters are separated by hyphens every three characters (triplet) during encoding.
/// During decoding, hyphens may be omitted or replaced with underscores.
/// Provides [`Triplet`](triplet::Triplet) and [`TripletError`](triplet::TripletError).
pub use Dtid;
pub use Error;
pub use Qtid;
pub use Stid;
pub use Ttid;
/// Provides message types generated by prost-build.
pub type StidMessage = Stid;
pub type DtidMessage = Dtid;
pub type TtidMessage = Ttid;
pub type QtidMessage = Qtid;
/// Alias of [`proto::Stid`]
pub type StidProto = Stid;
/// Alias of [`proto::Dtid`]
pub type DtidProto = Dtid;
/// Alias of [`proto::Ttid`]
pub type TtidProto = Ttid;
/// Alias of [`proto::Qtid`]
pub type QtidProto = Qtid;