ferroid/futures/
snowflake.rs1use super::SleepProvider;
2use crate::{IdGenStatus, Result, SnowflakeGenerator, SnowflakeId, TimeSource, ToU64};
3use core::{
4 fmt,
5 future::Future,
6 marker::PhantomData,
7 pin::Pin,
8 task::{Context, Poll},
9 time::Duration,
10};
11use pin_project_lite::pin_project;
12
13pub trait SnowflakeGeneratorAsyncExt<ID, T>
22where
23 ID: SnowflakeId,
24 T: TimeSource<ID::Ty>,
25{
26 type Err: fmt::Debug;
27
28 fn try_next_id_async<S>(&self) -> impl Future<Output = Result<ID, Self::Err>>
37 where
38 S: SleepProvider;
39}
40
41impl<G, ID, T> SnowflakeGeneratorAsyncExt<ID, T> for G
42where
43 G: SnowflakeGenerator<ID, T>,
44 ID: SnowflakeId,
45 T: TimeSource<ID::Ty>,
46{
47 type Err = G::Err;
48
49 #[allow(clippy::future_not_send)]
50 fn try_next_id_async<'a, S>(&'a self) -> impl Future<Output = Result<ID, Self::Err>>
51 where
52 S: SleepProvider,
53 {
54 SnowflakeGeneratorFuture::<'a, G, ID, T, S>::new(self)
55 }
56}
57
58pin_project! {
59 #[must_use = "futures do nothing unless you `.await` or poll them"]
65 pub struct SnowflakeGeneratorFuture<'a, G, ID, T, S>
66 where
67 G: SnowflakeGenerator<ID, T>,
68 ID: SnowflakeId,
69 T: TimeSource<ID::Ty>,
70 S: SleepProvider,
71 {
72 generator: &'a G,
73 #[pin]
74 sleep: Option<S::Sleep>,
75 _idt: PhantomData<(ID, T)>
76 }
77}
78
79impl<'a, G, ID, T, S> SnowflakeGeneratorFuture<'a, G, ID, T, S>
80where
81 G: SnowflakeGenerator<ID, T>,
82 ID: SnowflakeId,
83 T: TimeSource<ID::Ty>,
84 S: SleepProvider,
85{
86 pub const fn new(generator: &'a G) -> Self {
91 Self {
92 generator,
93 sleep: None,
94 _idt: PhantomData,
95 }
96 }
97}
98impl<G, ID, T, S> Future for SnowflakeGeneratorFuture<'_, G, ID, T, S>
99where
100 G: SnowflakeGenerator<ID, T>,
101 ID: SnowflakeId,
102 T: TimeSource<ID::Ty>,
103 S: SleepProvider,
104{
105 type Output = Result<ID, G::Err>;
106
107 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
112 let mut this = self.project();
113
114 if let Some(sleep) = this.sleep.as_mut().as_pin_mut() {
115 match sleep.poll(cx) {
116 Poll::Pending => {
117 return Poll::Pending;
118 }
119 Poll::Ready(()) => {
120 this.sleep.set(None);
121 }
122 }
123 }
124 match this.generator.try_next_id()? {
125 IdGenStatus::Ready { id } => Poll::Ready(Ok(id)),
126 IdGenStatus::Pending { yield_for } => {
127 let sleep_fut = S::sleep_for(Duration::from_millis(yield_for.to_u64()));
128 this.sleep.as_mut().set(Some(sleep_fut));
129 cx.waker().wake_by_ref();
130 Poll::Pending
131 }
132 }
133 }
134}