1use crate::{Result, Snowflake, SnowflakeGenerator, TimeSource, TokioSleep};
2
3pub trait SnowflakeGeneratorAsyncTokioExt<ID, T>
12where
13 ID: Snowflake,
14 T: TimeSource<ID::Ty>,
15{
16 fn try_next_id_async(&self) -> impl Future<Output = Result<ID>>;
30}
31
32impl<G, ID, T> SnowflakeGeneratorAsyncTokioExt<ID, T> for G
33where
34 G: SnowflakeGenerator<ID, T>,
35 ID: Snowflake,
36 T: TimeSource<ID::Ty>,
37{
38 fn try_next_id_async(&self) -> impl Future<Output = Result<ID>> {
39 <Self as crate::SnowflakeGeneratorAsyncExt<ID, T>>::try_next_id_async::<TokioSleep>(self)
40 }
41}
42
43#[cfg(test)]
44mod tests {
45 use super::*;
46 use crate::{
47 AtomicSnowflakeGenerator, LockSnowflakeGenerator, MonotonicClock, Result, SleepProvider,
48 Snowflake, SnowflakeGenerator, SnowflakeTwitterId, TimeSource, TokioYield,
49 };
50 use core::fmt;
51 use futures::future::try_join_all;
52 use std::collections::HashSet;
53
54 const TOTAL_IDS: usize = 4096;
55 const NUM_GENERATORS: u64 = 8;
56 const IDS_PER_GENERATOR: usize = TOTAL_IDS * 8; #[tokio::test(flavor = "multi_thread", worker_threads = 8)]
59 async fn generates_many_unique_ids_lock_sleep() -> Result<()> {
60 test_many_snow_unique_ids_explicit::<SnowflakeTwitterId, _, _, TokioSleep>(
61 LockSnowflakeGenerator::new,
62 MonotonicClock::default,
63 )
64 .await?;
65 Ok(())
66 }
67 #[tokio::test(flavor = "multi_thread", worker_threads = 8)]
68 async fn generates_many_unique_ids_lock_yield() -> Result<()> {
69 test_many_snow_unique_ids_explicit::<SnowflakeTwitterId, _, _, TokioYield>(
70 LockSnowflakeGenerator::new,
71 MonotonicClock::default,
72 )
73 .await?;
74 Ok(())
75 }
76 #[tokio::test(flavor = "multi_thread", worker_threads = 8)]
77 async fn generates_many_unique_ids_lock_convenience() -> Result<()> {
78 test_many_snow_unique_ids_convenience::<SnowflakeTwitterId, _, _>(
79 LockSnowflakeGenerator::new,
80 MonotonicClock::default,
81 )
82 .await?;
83 Ok(())
84 }
85
86 #[tokio::test(flavor = "multi_thread", worker_threads = 8)]
87 async fn generates_many_unique_ids_atomic_sleep() -> Result<()> {
88 test_many_snow_unique_ids_explicit::<SnowflakeTwitterId, _, _, TokioSleep>(
89 AtomicSnowflakeGenerator::new,
90 MonotonicClock::default,
91 )
92 .await?;
93 Ok(())
94 }
95 #[tokio::test(flavor = "multi_thread", worker_threads = 8)]
96 async fn generates_many_unique_ids_atomic_yield() -> Result<()> {
97 test_many_snow_unique_ids_explicit::<SnowflakeTwitterId, _, _, TokioYield>(
98 AtomicSnowflakeGenerator::new,
99 MonotonicClock::default,
100 )
101 .await?;
102 Ok(())
103 }
104 #[tokio::test(flavor = "multi_thread", worker_threads = 8)]
105 async fn generates_many_unique_ids_atomic_convenience() -> Result<()> {
106 test_many_snow_unique_ids_convenience::<SnowflakeTwitterId, _, _>(
107 AtomicSnowflakeGenerator::new,
108 MonotonicClock::default,
109 )
110 .await?;
111 Ok(())
112 }
113
114 async fn test_many_snow_unique_ids_explicit<ID, G, T, S>(
116 generator_fn: impl Fn(u64, T) -> G,
117 clock_factory: impl Fn() -> T,
118 ) -> Result<()>
119 where
120 G: SnowflakeGenerator<ID, T> + Send + Sync + 'static,
121 ID: Snowflake + fmt::Debug + Send + 'static,
122 T: TimeSource<ID::Ty> + Clone + Send,
123 S: SleepProvider,
124 {
125 let clock = clock_factory();
126 let generators: Vec<_> = (0..NUM_GENERATORS)
127 .map(|machine_id| generator_fn(machine_id, clock.clone()))
128 .collect();
129
130 let tasks: Vec<tokio::task::JoinHandle<Result<_>>> = generators
132 .into_iter()
133 .map(|g| {
134 tokio::spawn(async move {
135 let mut ids = Vec::with_capacity(IDS_PER_GENERATOR);
136 for _ in 0..IDS_PER_GENERATOR {
137 let id =
138 crate::SnowflakeGeneratorAsyncExt::try_next_id_async::<S>(&g).await?;
139 ids.push(id);
140 }
141 Ok(ids)
142 })
143 })
144 .collect();
145
146 validate_unique_snow_ids(tasks).await
147 }
148
149 async fn test_many_snow_unique_ids_convenience<ID, G, T>(
151 generator_fn: impl Fn(u64, T) -> G,
152 clock_factory: impl Fn() -> T,
153 ) -> Result<()>
154 where
155 G: SnowflakeGenerator<ID, T> + Send + Sync + 'static,
156 ID: Snowflake + fmt::Debug + Send + 'static,
157 T: TimeSource<ID::Ty> + Clone + Send,
158 {
159 let clock = clock_factory();
160 let generators: Vec<_> = (0..NUM_GENERATORS)
161 .map(|machine_id| generator_fn(machine_id, clock.clone()))
162 .collect();
163
164 let tasks: Vec<tokio::task::JoinHandle<Result<_>>> = generators
166 .into_iter()
167 .map(|g| {
168 tokio::spawn(async move {
169 let mut ids = Vec::with_capacity(IDS_PER_GENERATOR);
170 for _ in 0..IDS_PER_GENERATOR {
171 let id = g.try_next_id_async().await?;
174 ids.push(id);
175 }
176 Ok(ids)
177 })
178 })
179 .collect();
180
181 validate_unique_snow_ids(tasks).await
182 }
183
184 async fn validate_unique_snow_ids(
186 tasks: Vec<tokio::task::JoinHandle<Result<Vec<impl Snowflake + fmt::Debug>>>>,
187 ) -> Result<()> {
188 let all_ids: Vec<_> = try_join_all(tasks)
189 .await
190 .unwrap()
191 .into_iter()
192 .flat_map(Result::unwrap)
193 .collect();
194
195 let expected_total = NUM_GENERATORS as usize * IDS_PER_GENERATOR;
196 assert_eq!(
197 all_ids.len(),
198 expected_total,
199 "Expected {} IDs but got {}",
200 expected_total,
201 all_ids.len()
202 );
203
204 let mut seen = HashSet::with_capacity(all_ids.len());
205 for id in &all_ids {
206 assert!(seen.insert(id), "Duplicate ID found: {id:?}");
207 }
208
209 Ok(())
210 }
211}