1
1
// Copyright (c) The future-queue Contributors
2
2
// SPDX-License-Identifier: MIT OR Apache-2.0
3
3
4
- use crate :: { global_weight:: GlobalWeight , peekable_fused:: PeekableFused } ;
4
+ use crate :: {
5
+ global_weight:: GlobalWeight , peekable_fused:: PeekableFused , slots:: SlotReservations ,
6
+ FutureQueueContext ,
7
+ } ;
5
8
use futures_util:: {
6
9
stream:: { Fuse , FuturesUnordered } ,
7
10
Future , Stream , StreamExt as _,
@@ -24,6 +27,7 @@ pin_project! {
24
27
#[ pin]
25
28
stream: PeekableFused <Fuse <St >>,
26
29
in_progress_queue: FuturesUnordered <FutureWithWeight <<St :: Item as WeightedFuture >:: Future >>,
30
+ slots: SlotReservations ,
27
31
global_weight: GlobalWeight ,
28
32
}
29
33
}
37
41
f. debug_struct ( "FutureQueue" )
38
42
. field ( "stream" , & self . stream )
39
43
. field ( "in_progress_queue" , & self . in_progress_queue )
44
+ . field ( "slots" , & self . slots )
40
45
. field ( "global_weight" , & self . global_weight )
41
46
. finish ( )
42
47
}
@@ -51,10 +56,17 @@ where
51
56
Self {
52
57
stream : PeekableFused :: new ( stream. fuse ( ) ) ,
53
58
in_progress_queue : FuturesUnordered :: new ( ) ,
59
+ slots : SlotReservations :: with_capacity ( max_weight) ,
54
60
global_weight : GlobalWeight :: new ( max_weight) ,
55
61
}
56
62
}
57
63
64
+ /// Sets a mode where extra internal verifications are performed.
65
+ #[ doc( hidden) ]
66
+ pub fn set_extra_verify ( & mut self , verify : bool ) {
67
+ self . slots . set_check_reserved ( verify) ;
68
+ }
69
+
58
70
/// Returns the maximum weight of futures allowed to be run by this adaptor.
59
71
pub fn max_weight ( & self ) -> usize {
60
72
self . global_weight . max ( )
@@ -117,20 +129,29 @@ where
117
129
break ;
118
130
}
119
131
120
- let ( weight, future ) = match this. stream . as_mut ( ) . poll_next ( cx) {
132
+ let ( weight, future_fn ) = match this. stream . as_mut ( ) . poll_next ( cx) {
121
133
Poll :: Ready ( Some ( weighted_future) ) => weighted_future. into_components ( ) ,
122
134
_ => unreachable ! ( "we just peeked at this item" ) ,
123
135
} ;
124
136
this. global_weight . add_weight ( weight) ;
137
+ let global_slot = this. slots . reserve ( ) ;
138
+
139
+ let cx = FutureQueueContext {
140
+ global_slot,
141
+ group_slot : None ,
142
+ } ;
143
+ let future = future_fn ( cx) ;
144
+
125
145
this. in_progress_queue
126
- . push ( FutureWithWeight :: new ( weight, future) ) ;
146
+ . push ( FutureWithWeight :: new ( weight, global_slot , future) ) ;
127
147
}
128
148
129
149
// Attempt to pull the next value from the in_progress_queue.
130
150
match this. in_progress_queue . poll_next_unpin ( cx) {
131
151
Poll :: Pending => return Poll :: Pending ,
132
- Poll :: Ready ( Some ( ( weight, output) ) ) => {
152
+ Poll :: Ready ( Some ( ( weight, slot , output) ) ) => {
133
153
this. global_weight . sub_weight ( weight) ;
154
+ this. slots . release ( slot) ;
134
155
return Poll :: Ready ( Some ( output) ) ;
135
156
}
136
157
Poll :: Ready ( None ) => { }
@@ -160,26 +181,36 @@ where
160
181
///
161
182
/// Provided in case it's necessary. This trait is only implemented for `(usize, impl Future)`.
162
183
pub trait WeightedFuture : private:: Sealed {
184
+ /// The function to obtain the future from
185
+ type F : FnOnce ( FutureQueueContext ) -> Self :: Future ;
186
+
163
187
/// The associated `Future` type.
164
188
type Future : Future ;
165
189
166
190
/// The weight of the future.
167
191
fn weight ( & self ) -> usize ;
168
192
169
193
/// Turns self into its components.
170
- fn into_components ( self ) -> ( usize , Self :: Future ) ;
194
+ fn into_components ( self ) -> ( usize , Self :: F ) ;
171
195
}
172
196
173
197
mod private {
174
198
pub trait Sealed { }
175
199
}
176
200
177
- impl < Fut > private:: Sealed for ( usize , Fut ) where Fut : Future { }
201
+ impl < F , Fut > private:: Sealed for ( usize , F )
202
+ where
203
+ F : FnOnce ( FutureQueueContext ) -> Fut ,
204
+ Fut : Future ,
205
+ {
206
+ }
178
207
179
- impl < Fut > WeightedFuture for ( usize , Fut )
208
+ impl < F , Fut > WeightedFuture for ( usize , F )
180
209
where
210
+ F : FnOnce ( FutureQueueContext ) -> Fut ,
181
211
Fut : Future ,
182
212
{
213
+ type F = F ;
183
214
type Future = Fut ;
184
215
185
216
#[ inline]
@@ -188,7 +219,7 @@ where
188
219
}
189
220
190
221
#[ inline]
191
- fn into_components ( self ) -> ( usize , Self :: Future ) {
222
+ fn into_components ( self ) -> ( usize , Self :: F ) {
192
223
self
193
224
}
194
225
}
@@ -199,26 +230,31 @@ pin_project! {
199
230
#[ pin]
200
231
future: Fut ,
201
232
weight: usize ,
233
+ slot: u64 ,
202
234
}
203
235
}
204
236
205
237
impl < Fut > FutureWithWeight < Fut > {
206
- pub fn new ( weight : usize , future : Fut ) -> Self {
207
- Self { future, weight }
238
+ pub fn new ( weight : usize , slot : u64 , future : Fut ) -> Self {
239
+ Self {
240
+ future,
241
+ weight,
242
+ slot,
243
+ }
208
244
}
209
245
}
210
246
211
247
impl < Fut > Future for FutureWithWeight < Fut >
212
248
where
213
249
Fut : Future ,
214
250
{
215
- type Output = ( usize , Fut :: Output ) ;
251
+ type Output = ( usize , u64 , Fut :: Output ) ;
216
252
fn poll ( self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Self :: Output > {
217
253
let this = self . project ( ) ;
218
254
219
255
match this. future . poll ( cx) {
220
256
Poll :: Pending => Poll :: Pending ,
221
- Poll :: Ready ( output) => Poll :: Ready ( ( * this. weight , output) ) ,
257
+ Poll :: Ready ( output) => Poll :: Ready ( ( * this. weight , * this . slot , output) ) ,
222
258
}
223
259
}
224
260
}
0 commit comments