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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
// Copyright 2022 houseme
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A high-performance, highly concurrent, distributed Snowflake ID generator.
//!
//! This implementation is **lock-free**, designed for maximum throughput and minimum latency on multi-core CPUs.
//!
//! ## Highlights
//!
//! - **Lock-Free Concurrency**: Uses `AtomicU64` and CAS operations to manage internal state, eliminating `Mutex` lock overhead.
//! - **High Performance**: The lock-free design makes ID generation extremely fast, performing exceptionally well under high concurrency.
//! - **Highly Customizable**: The `Builder` pattern allows you to flexibly configure the start time, machine ID, data center ID, and the bit lengths of each component.
//! - **Smart IP Fallback**: With the `ip-fallback` feature enabled, if `machine_id` or `data_center_id` are not provided, the system automatically derives them from local network interfaces.
//! - **Supports both IPv4 and IPv6**: It prioritizes private IPv4 addresses and falls back to private IPv6 addresses.
//! - **Conflict-Free**: To ensure uniqueness, `machine_id` and `data_center_id` are derived from distinct parts of the IP address.
//! - **`no_std` Support**: Works in `no_std` + `alloc` environments with a user-provided time source.
//!
//! ## Architecture
//!
//! A Snowflake ID is a 64-bit integer composed of four sections:
//!
//! ```text
//! ┌─────────────────────────────────────────────────────────────────┐
//! │ 0 │ 41 bits: time │ 5 bits: dc │ 5 bits: machine │ 12 bits: seq │
//! └─────────────────────────────────────────────────────────────────┘
//! ↑ │
//! sign bit (always 0) │
//! ```
//!
//! - **Time** (41 bits): Milliseconds since the configured start time. Default epoch is 2022-01-01.
//! - **Data Center ID** (5 bits): Identifies the data center (0–31).
//! - **Machine ID** (5 bits): Identifies the machine within the data center (0–31).
//! - **Sequence** (12 bits): Per-millisecond counter (0–4095).
//!
//! The bit lengths are fully configurable via [`Builder`], as long as they sum to 63.
//!
//! ## Performance
//!
//! The generator uses a lock-free CAS (Compare-And-Swap) loop with cache-line aligned state
//! (`#[repr(align(64))]`) to prevent false sharing between threads. Under contention, it
//! defaults to `compare_exchange_weak` which allows spurious failures for better throughput
//! on ARM and other architectures. Enable the `use-strong-cas` feature to use
//! `compare_exchange` instead.
//!
//! ## Thread Safety
//!
//! [`Snowflake`] is safe to `Clone` and share across threads. Cloning is a cheap `Arc`
//! increment — all clones share the same internal state. The [`next_id`](Snowflake::next_id)
//! method is lock-free and safe to call concurrently from any number of threads.
//!
//! ## Feature Flags
//!
//! | Feature | Dependencies | Default | Description |
//! |---------|-------------|---------|-------------|
//! | `std` | chrono, thiserror/std | Yes | Standard library support (time via chrono) |
//! | `ip-fallback` | std, pnet_datalink | No | Auto-derive IDs from local IP address |
//! | `serde` | serde | No | Serde serialization for `SnowflakeId` and `DecomposedSnowflake` |
//! | `tracing` | tracing | No | Structured logging at key points |
//! | `metrics` | metrics | No | Runtime counters and gauges |
//! | `use-strong-cas` | — | No | Use `compare_exchange` instead of `compare_exchange_weak` |
//! | `full` | all of the above | No | Enable all optional features |
//!
//! ## Quick Start
//!
//! ### 1. Add Dependency
//!
//! Add this to your `Cargo.toml`. To use automatic IP-based configuration, enable the `ip-fallback` feature.
//!
//! ```toml
//! [dependencies]
//! snowflake-me = { version = "1.0", features = ["ip-fallback"] }
//! ```
//!
//! ### 2. Basic Usage
//!
//! ```rust
//! use snowflake_me::Snowflake;
//!
//! // Create a generator with the default configuration.
//! // Note: This requires the `ip-fallback` feature to auto-detect machine and data center IDs.
//! # #[cfg(feature = "ip-fallback")]
//! # {
//! let sf = Snowflake::new().unwrap();
//! let next_id = sf.next_id().unwrap();
//! println!("Generated ID: {}", next_id);
//! # }
//! ```
//!
//! ## Recommended Usage for Production
//!
//! For production environments, it is highly recommended to use the `Builder` to manually configure `machine_id` and `data_center_id` for maximum reliability.
//!
//! ```rust
//! # #[cfg(feature = "std")] {
//! use snowflake_me::Snowflake;
//! use std::thread;
//! use std::sync::Arc;
//! use std::collections::HashSet;
//!
//! // Manually configure IDs for reliability.
//! let sf = Snowflake::builder()
//! .machine_id(&|| Ok(10))
//! .data_center_id(&|| Ok(5))
//! .finalize()
//! .unwrap();
//!
//! let sf_arc = Arc::new(sf);
//! let mut handles = vec![];
//!
//! for _ in 0..10 {
//! let sf_clone = Arc::clone(&sf_arc);
//! let handle = thread::spawn(move || {
//! let mut ids = Vec::new();
//! for _ in 0..1000 {
//! ids.push(sf_clone.next_id().unwrap());
//! }
//! ids
//! });
//! handles.push(handle);
//! }
//!
//! let mut all_ids = HashSet::new();
//! for handle in handles {
//! let ids = handle.join().unwrap();
//! for id in ids {
//! // Verify that all IDs are unique
//! assert!(all_ids.insert(id), "Found duplicate ID: {}", id);
//! }
//! }
//!
//! println!("Successfully generated {} unique IDs.", all_ids.len());
//! # }
//! ```
//!
//! ## Decomposing an ID
//!
//! You can decompose a Snowflake ID back into its original components.
//!
//! ```rust
//! # #[cfg(feature = "std")] {
//! use snowflake_me::{Snowflake, DecomposedSnowflake};
//!
//! // Use the same configuration that was used for generation.
//! let sf = Snowflake::builder()
//! .machine_id(&|| Ok(15))
//! .data_center_id(&|| Ok(7))
//! .finalize()
//! .unwrap();
//!
//! let id = sf.next_id().unwrap();
//!
//! // Decompose the ID using the generator's configuration.
//! let decomposed = sf.decompose(id);
//!
//! println!("ID: {}", decomposed.id);
//! println!("Time: {}", decomposed.time);
//! println!("Data Center ID: {}", decomposed.data_center_id);
//! println!("Machine ID: {}", decomposed.machine_id);
//! println!("Sequence: {}", decomposed.sequence);
//!
//! assert_eq!(decomposed.machine_id, 15);
//! assert_eq!(decomposed.data_center_id, 7);
//! # }
//! ```
//!
//! ## Clock Drift Protection
//!
//! If the system clock moves backward (e.g., due to NTP adjustments), the generator
//! can handle it using one of three strategies:
//!
//! ```rust
//! use snowflake_me::{Snowflake, ClockDriftStrategy};
//!
//! let sf = Snowflake::builder()
//! .machine_id(&|| Ok(1))
//! .data_center_id(&|| Ok(1))
//! .clock_drift_strategy(ClockDriftStrategy::Wait)
//! .max_clock_drift_ms(5000) // fail if drift > 5 seconds
//! .finalize()
//! .unwrap();
//! ```
//!
//! See [`ClockDriftStrategy`] for details on each strategy.
//!
//! ## `no_std` Usage
//!
//! In `no_std` environments, disable default features and provide a time source:
//!
//! ```rust,ignore
//! // In your timer interrupt or main loop:
//! snowflake_me::set_time_source(current_millis);
//!
//! // Then create the generator (start_time must be a raw i64 in milliseconds):
//! let sf = Snowflake::builder()
//! .start_time(1_640_995_200_000) // 2022-01-01 UTC
//! .machine_id(&|| Ok(1))
//! .data_center_id(&|| Ok(1))
//! .finalize()
//! .unwrap();
//! ```
//!
//! [Twitter's Snowflake]: https://blog.twitter.com/2010/announcing-snowflake
;
/// Clock drift handling strategies for backward clock detection.
/// The [`SnowflakeId`] newtype with encoding methods and trait implementations.
pub
pub use Builder;
pub use ClockDriftStrategy;
pub use Error;
pub use SnowflakeId;
pub use SnowflakeIdString;
pub use ;
pub use set_time_source;