1use crate::inner::{InnerPool, TokenFetcher};
2use crate::InterruptedReason;
3use std::cell::RefCell;
4use std::collections::HashSet;
5use std::future::Future;
6use std::pin::Pin;
7use std::sync::Arc;
8use std::task::{Context, Poll};
9
10thread_local!(
11 static PERMIT_SET: RefCell<HashSet<usize>> = RefCell::new(HashSet::new());
12);
13
14pub(crate) trait TokenHolder {
15 fn render_token(&mut self);
16}
17
18#[deprecated(
19 since = "0.1.4",
20 note = "\
21 The `Permit` is going to be deprecated in favor of calling GateKeeper's `issue()` method \
22 to guard the gate. This struct, along with the associated API (i.e. `register()`), will be
23 removed in the 0.1.5 release.
24 "
25)]
26pub struct Permit<R, F>
27where
28 R: Send + 'static,
29 F: Future<Output = R> + 'static,
30{
31 fut: F,
32 pool: Arc<InnerPool>,
33}
34
35impl<R, F> Permit<R, F>
36where
37 R: Send + 'static,
38 F: Future<Output = R> + 'static,
39{
40 pub(crate) fn new(fut: F, pool: Arc<InnerPool>) -> Self {
41 Permit { fut, pool }
42 }
43}
44
45impl<R, F> Future for Permit<R, F>
46where
47 R: Send + 'static,
48 F: std::future::Future<Output = R> + 'static,
49{
50 type Output = R;
51
52 fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
53 let (fut, pool) = unsafe {
55 let ptr = Pin::get_unchecked_mut(self);
56
57 (Pin::new_unchecked(&mut ptr.fut), &ptr.pool)
58 };
59
60 let pool_id = pool.get_id();
62
63 let need_token = PERMIT_SET.with(|set| !set.borrow().contains(&pool_id));
65
66 if need_token {
68 pool.request_token(false);
69
70 PERMIT_SET.with(|set| {
71 (*set.borrow_mut()).insert(pool_id);
72 });
73 }
74
75 let res = fut.poll(ctx);
77
78 if need_token {
80 PERMIT_SET.with(|set| {
81 (*set.borrow_mut()).remove(&pool_id);
82 });
83
84 pool.return_token();
85 }
86
87 res
88 }
89}
90
91pub(crate) struct Ticket<R, F>
92where
93 R: Send + 'static,
94 F: Future<Output = R> + 'static,
95{
96 pool_id: usize,
97 token_obtained: bool,
98 pool: Option<Arc<InnerPool>>,
99 fut: Option<Pin<Box<F>>>,
100}
101
102impl<R, F> Ticket<R, F>
103where
104 R: Send + 'static,
105 F: Future<Output = R> + 'static,
106{
107 pub(crate) fn new(pool: Arc<InnerPool>, fut: Option<F>) -> Self {
108 Ticket {
109 pool_id: 0,
110 token_obtained: false,
111 pool: Some(pool),
112 fut: fut.map(Box::pin),
113 }
114 }
115
116 fn request_token(&mut self) -> bool {
117 assert!(
118 !self.token_obtained,
119 "failed to return previously obtained token ... "
120 );
121
122 if let Some(pool) = self.pool.as_mut() {
123 if pool.request_token(true) {
124 let pool_id = pool.get_id();
125
126 PERMIT_SET.with(|set| {
127 set.borrow_mut().insert(pool_id);
128 });
129
130 self.pool_id = pool_id;
131 self.token_obtained = true;
132
133 return true;
134 }
135 }
136
137 false
138 }
139
140 fn make_stub(&mut self) -> TicketStub {
141 self.token_obtained = false;
144
145 TicketStub {
147 pool: self.pool.take().unwrap(),
148 }
149 }
150}
151
152impl<R, F> TokenHolder for Ticket<R, F>
153where
154 R: Send + 'static,
155 F: Future<Output = R> + 'static,
156{
157 fn render_token(&mut self) {
158 if let Some(pool) = self.pool.as_ref() {
159 assert!(
162 self.token_obtained,
163 "failed at double-returning a previously obtained token ... "
164 );
165
166 pool.return_token();
167
168 PERMIT_SET.with(|set| {
169 set.borrow_mut().remove(&self.pool_id);
170 });
171
172 self.token_obtained = false;
173 }
174 }
175}
176
177impl<R, F> Drop for Ticket<R, F>
178where
179 R: Send + 'static,
180 F: Future<Output = R> + 'static,
181{
182 fn drop(&mut self) {
183 self.render_token();
184 }
185}
186
187impl<R, F> Future for Ticket<R, F>
188where
189 R: Send + 'static,
190 F: Future<Output = R> + 'static,
191{
192 type Output = Result<(Option<TicketStub>, Option<R>), InterruptedReason>;
193
194 fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
195 assert!(
196 self.pool.is_some(),
197 "The pass has already been issued, yet the ticket is polled for access again ... "
198 );
199
200 let ref_this = self.get_mut();
204
205 let need_token = if ref_this.pool_id == 0 {
207 true
208 } else {
209 PERMIT_SET.with(|set|
210 !set.borrow().contains(&ref_this.pool_id)
211 )
212 };
213
214 if !need_token || ref_this.request_token() {
215 if let Some(fut) = ref_this.fut.as_mut() {
220 return match fut.as_mut().poll(ctx) {
221 Poll::Pending => {
222 if need_token {
226 ref_this.render_token();
227 }
228
229 Poll::Pending
230 }
231 Poll::Ready(val) => {
232 Poll::Ready(Ok((
234 None,
235 Some(val)
236 )))
237 }
238 };
239 }
240
241 return Poll::Ready(Ok((
248 Some(ref_this.make_stub()),
249 None
250 )));
251 }
252
253 if let Some(pool) = ref_this.pool.as_ref() {
255 if ref_this.fut.is_none() {
258 pool.enqueue(ctx.waker().clone());
259 }
260 }
261
262 Poll::Pending
263 }
264}
265
266pub(crate) struct TicketStub {
267 pool: Arc<InnerPool>,
268}
269
270impl TokenHolder for TicketStub {
271 fn render_token(&mut self) {
272 self.pool.return_token();
273 }
274}
275
276impl Drop for TicketStub {
277 fn drop(&mut self) {
278 self.render_token();
281 }
282}