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
//! Snowflake-style IDs as distinct, validated newtypes.
//!
//! Declare an ID type with [`#[typedflake]`](macro@typedflake), install a node
//! once with [`init`], and generate IDs anywhere:
//!
//! ```
//! use typedflake::typedflake;
//!
//! #[typedflake(epoch = "2025-01-01")]
//! pub struct UserId(i64);
//!
//! #[typedflake(epoch = "2025-01-01")]
//! pub struct OrderId(i64);
//!
//! // Once, during application startup.
//! typedflake::init(17)?;
//!
//! // Anywhere in the application.
//! let user_id = UserId::generate()?;
//! let order_id = OrderId::generate()?;
//!
//! assert_eq!(user_id.parts().node, 17);
//! assert_eq!(order_id.to_string().parse::<OrderId>()?, order_id);
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! `UserId` and `OrderId` are separate types: they cannot be mixed up, and each
//! keeps its own generation state.
//!
//! # Uniqueness
//!
//! IDs of one type are unique as long as no two running processes use the same
//! node for it, and the system clock does not move backwards across a restart.
//! This crate does not assign nodes or coordinate deployments.
//!
//! # Features
//!
//! | Feature | Enables |
//! | --- | --- |
//! | `serde` | [`Serde`](macro@Serde) and [`SerdeEncoded`](macro@SerdeEncoded) derives |
//! | `sqlx-postgres` | [`SqlxPostgres`](macro@SqlxPostgres) derive |
//! | `postgres` | [`Postgres`](macro@Postgres) derive for `postgres-types` |
//! | `tokio` | `generate_async` methods |
compile_error!;
// Generated code refers to `::typedflake`, including inside this crate.
extern crate self as typedflake;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
/// Support for generated code. Not part of the public interface.
/// Compiles the README's examples as doctests. They use every integration, so
/// they only run with all features enabled.
;
;
/// Rejections whose compiler output depends on whether the standard library's
/// sources are installed, so they are checked here instead of in `tests/ui`.
///
/// IDs have no arithmetic:
///
/// ```compile_fail
/// use typedflake::typedflake;
///
/// #[typedflake(epoch = "2025-01-01")]
/// struct UserId(i64);
///
/// let id = UserId::try_from(1_i64).unwrap();
/// let next = id + 1;
/// ```
///
/// A date that does not exist fails a const epoch:
///
/// ```compile_fail
/// const EPOCH: typedflake::Epoch = typedflake::Epoch::from_date(2025, 2, 30);
/// ```
///
/// An alphabet with a repeated character fails at the declaration that uses
/// it, even if nothing is ever encoded:
///
/// ```compile_fail
/// use typedflake::{Alphabet, typedflake};
///
/// #[typedflake(epoch = "2025-01-01", alphabet = Alphabet::new("abca"))]
/// struct LinkId(i64);
/// ```
///
/// The same declarations compile once corrected:
///
/// ```
/// use typedflake::{Alphabet, typedflake};
///
/// #[typedflake(epoch = "2025-01-01")]
/// struct UserId(i64);
///
/// let id = UserId::try_from(1_i64).unwrap();
/// let next = id.get() + 1;
/// const EPOCH: typedflake::Epoch = typedflake::Epoch::from_date(2025, 2, 28);
///
/// #[typedflake(epoch = "2025-01-01", alphabet = Alphabet::new("abc"))]
/// struct LinkId(i64);
/// # let _ = (next, EPOCH);
/// ```
;