11// Copyright (c) The future-queue Contributors
22// SPDX-License-Identifier: MIT OR Apache-2.0
33
4- use crate :: { global_weight:: GlobalWeight , peekable_fused:: PeekableFused } ;
4+ use crate :: {
5+ global_weight:: GlobalWeight , peekable_fused:: PeekableFused , slots:: SlotReservations ,
6+ FutureQueueContext ,
7+ } ;
58use futures_util:: {
69 stream:: { Fuse , FuturesUnordered } ,
710 Future , Stream , StreamExt as _,
@@ -24,6 +27,7 @@ pin_project! {
2427 #[ pin]
2528 stream: PeekableFused <Fuse <St >>,
2629 in_progress_queue: FuturesUnordered <FutureWithWeight <<St :: Item as WeightedFuture >:: Future >>,
30+ slots: SlotReservations ,
2731 global_weight: GlobalWeight ,
2832 }
2933}
3741 f. debug_struct ( "FutureQueue" )
3842 . field ( "stream" , & self . stream )
3943 . field ( "in_progress_queue" , & self . in_progress_queue )
44+ . field ( "slots" , & self . slots )
4045 . field ( "global_weight" , & self . global_weight )
4146 . finish ( )
4247 }
@@ -51,10 +56,17 @@ where
5156 Self {
5257 stream : PeekableFused :: new ( stream. fuse ( ) ) ,
5358 in_progress_queue : FuturesUnordered :: new ( ) ,
59+ slots : SlotReservations :: with_capacity ( max_weight) ,
5460 global_weight : GlobalWeight :: new ( max_weight) ,
5561 }
5662 }
5763
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+
5870 /// Returns the maximum weight of futures allowed to be run by this adaptor.
5971 pub fn max_weight ( & self ) -> usize {
6072 self . global_weight . max ( )
@@ -117,20 +129,29 @@ where
117129 break ;
118130 }
119131
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) {
121133 Poll :: Ready ( Some ( weighted_future) ) => weighted_future. into_components ( ) ,
122134 _ => unreachable ! ( "we just peeked at this item" ) ,
123135 } ;
124136 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+
125145 this. in_progress_queue
126- . push ( FutureWithWeight :: new ( weight, future) ) ;
146+ . push ( FutureWithWeight :: new ( weight, global_slot , future) ) ;
127147 }
128148
129149 // Attempt to pull the next value from the in_progress_queue.
130150 match this. in_progress_queue . poll_next_unpin ( cx) {
131151 Poll :: Pending => return Poll :: Pending ,
132- Poll :: Ready ( Some ( ( weight, output) ) ) => {
152+ Poll :: Ready ( Some ( ( weight, slot , output) ) ) => {
133153 this. global_weight . sub_weight ( weight) ;
154+ this. slots . release ( slot) ;
134155 return Poll :: Ready ( Some ( output) ) ;
135156 }
136157 Poll :: Ready ( None ) => { }
@@ -160,26 +181,36 @@ where
160181///
161182/// Provided in case it's necessary. This trait is only implemented for `(usize, impl Future)`.
162183pub trait WeightedFuture : private:: Sealed {
184+ /// The function to obtain the future from
185+ type F : FnOnce ( FutureQueueContext ) -> Self :: Future ;
186+
163187 /// The associated `Future` type.
164188 type Future : Future ;
165189
166190 /// The weight of the future.
167191 fn weight ( & self ) -> usize ;
168192
169193 /// Turns self into its components.
170- fn into_components ( self ) -> ( usize , Self :: Future ) ;
194+ fn into_components ( self ) -> ( usize , Self :: F ) ;
171195}
172196
173197mod private {
174198 pub trait Sealed { }
175199}
176200
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+ }
178207
179- impl < Fut > WeightedFuture for ( usize , Fut )
208+ impl < F , Fut > WeightedFuture for ( usize , F )
180209where
210+ F : FnOnce ( FutureQueueContext ) -> Fut ,
181211 Fut : Future ,
182212{
213+ type F = F ;
183214 type Future = Fut ;
184215
185216 #[ inline]
@@ -188,7 +219,7 @@ where
188219 }
189220
190221 #[ inline]
191- fn into_components ( self ) -> ( usize , Self :: Future ) {
222+ fn into_components ( self ) -> ( usize , Self :: F ) {
192223 self
193224 }
194225}
@@ -199,26 +230,31 @@ pin_project! {
199230 #[ pin]
200231 future: Fut ,
201232 weight: usize ,
233+ slot: u64 ,
202234 }
203235}
204236
205237impl < 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+ }
208244 }
209245}
210246
211247impl < Fut > Future for FutureWithWeight < Fut >
212248where
213249 Fut : Future ,
214250{
215- type Output = ( usize , Fut :: Output ) ;
251+ type Output = ( usize , u64 , Fut :: Output ) ;
216252 fn poll ( self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Self :: Output > {
217253 let this = self . project ( ) ;
218254
219255 match this. future . poll ( cx) {
220256 Poll :: Pending => Poll :: Pending ,
221- Poll :: Ready ( output) => Poll :: Ready ( ( * this. weight , output) ) ,
257+ Poll :: Ready ( output) => Poll :: Ready ( ( * this. weight , * this . slot , output) ) ,
222258 }
223259 }
224260}
0 commit comments