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
5
use futures_util:: {
5
6
stream:: { Fuse , FuturesUnordered } ,
6
7
Future , Stream , StreamExt as _,
@@ -21,10 +22,9 @@ pin_project! {
21
22
St :: Item : WeightedFuture ,
22
23
{
23
24
#[ pin]
24
- stream: Fuse <St >,
25
+ stream: PeekableFused < Fuse <St > >,
25
26
in_progress_queue: FuturesUnordered <FutureWithWeight <<St :: Item as WeightedFuture >:: Future >>,
26
- max_weight: usize ,
27
- current_weight: usize ,
27
+ global_weight: GlobalWeight ,
28
28
}
29
29
}
30
30
37
37
f. debug_struct ( "FutureQueue" )
38
38
. field ( "stream" , & self . stream )
39
39
. field ( "in_progress_queue" , & self . in_progress_queue )
40
- . field ( "max_weight" , & self . max_weight )
41
- . field ( "current_weight" , & self . current_weight )
40
+ . field ( "global_weight" , & self . global_weight )
42
41
. finish ( )
43
42
}
44
43
}
@@ -50,27 +49,26 @@ where
50
49
{
51
50
pub ( crate ) fn new ( stream : St , max_weight : usize ) -> Self {
52
51
Self {
53
- stream : stream. fuse ( ) ,
52
+ stream : PeekableFused :: new ( stream. fuse ( ) ) ,
54
53
in_progress_queue : FuturesUnordered :: new ( ) ,
55
- max_weight,
56
- current_weight : 0 ,
54
+ global_weight : GlobalWeight :: new ( max_weight) ,
57
55
}
58
56
}
59
57
60
58
/// Returns the maximum weight of futures allowed to be run by this adaptor.
61
59
pub fn max_weight ( & self ) -> usize {
62
- self . max_weight
60
+ self . global_weight . max ( )
63
61
}
64
62
65
63
/// Returns the currently running weight of futures.
66
64
pub fn current_weight ( & self ) -> usize {
67
- self . current_weight
65
+ self . global_weight . current ( )
68
66
}
69
67
70
68
/// Acquires a reference to the underlying sink or stream that this combinator is
71
69
/// pulling from.
72
70
pub fn get_ref ( & self ) -> & St {
73
- self . stream . get_ref ( )
71
+ self . stream . get_ref ( ) . get_ref ( )
74
72
}
75
73
76
74
/// Acquires a mutable reference to the underlying sink or stream that this
79
77
/// Note that care must be taken to avoid tampering with the state of the
80
78
/// sink or stream which may otherwise confuse this combinator.
81
79
pub fn get_mut ( & mut self ) -> & mut St {
82
- self . stream . get_mut ( )
80
+ self . stream . get_mut ( ) . get_mut ( )
83
81
}
84
82
85
83
/// Acquires a pinned mutable reference to the underlying sink or stream that this
@@ -88,15 +86,15 @@ where
88
86
/// Note that care must be taken to avoid tampering with the state of the
89
87
/// sink or stream which may otherwise confuse this combinator.
90
88
pub fn get_pin_mut ( self : Pin < & mut Self > ) -> core:: pin:: Pin < & mut St > {
91
- self . project ( ) . stream . get_pin_mut ( )
89
+ self . project ( ) . stream . get_pin_mut ( ) . get_pin_mut ( )
92
90
}
93
91
94
92
/// Consumes this combinator, returning the underlying sink or stream.
95
93
///
96
94
/// Note that this may discard intermediate state of this combinator, so
97
95
/// care should be taken to avoid losing resources when this is called.
98
96
pub fn into_inner ( self ) -> St {
99
- self . stream . into_inner ( )
97
+ self . stream . into_inner ( ) . into_inner ( )
100
98
}
101
99
}
102
100
@@ -112,35 +110,27 @@ where
112
110
113
111
// First up, try to spawn off as many futures as possible by filling up
114
112
// our queue of futures.
115
- while * this. current_weight < * this. max_weight {
116
- match this. stream . as_mut ( ) . poll_next ( cx) {
117
- Poll :: Ready ( Some ( weighted_future) ) => {
118
- let ( weight, future) = weighted_future. into_components ( ) ;
119
- * this. current_weight =
120
- this. current_weight . checked_add ( weight) . unwrap_or_else ( || {
121
- panic ! (
122
- "future_queue: added weight {} to current {}, overflowed" ,
123
- weight, this. current_weight,
124
- )
125
- } ) ;
126
- this. in_progress_queue
127
- . push ( FutureWithWeight :: new ( weight, future) ) ;
128
- }
129
- Poll :: Ready ( None ) | Poll :: Pending => break ,
113
+ while let Poll :: Ready ( Some ( weighted_future) ) = this. stream . as_mut ( ) . poll_peek ( cx) {
114
+ if !this. global_weight . has_space_for ( weighted_future. weight ( ) ) {
115
+ // Global limits would be exceeded, break out of the loop. Consider this
116
+ // item next time.
117
+ break ;
130
118
}
119
+
120
+ let ( weight, future) = match this. stream . as_mut ( ) . poll_next ( cx) {
121
+ Poll :: Ready ( Some ( weighted_future) ) => weighted_future. into_components ( ) ,
122
+ _ => unreachable ! ( "we just peeked at this item" ) ,
123
+ } ;
124
+ this. global_weight . add_weight ( weight) ;
125
+ this. in_progress_queue
126
+ . push ( FutureWithWeight :: new ( weight, future) ) ;
131
127
}
132
128
133
- // Attempt to pull the next value from the in_progress_queue
129
+ // Attempt to pull the next value from the in_progress_queue.
134
130
match this. in_progress_queue . poll_next_unpin ( cx) {
135
131
Poll :: Pending => return Poll :: Pending ,
136
132
Poll :: Ready ( Some ( ( weight, output) ) ) => {
137
- * this. current_weight =
138
- this. current_weight . checked_sub ( weight) . unwrap_or_else ( || {
139
- panic ! (
140
- "future_queue: subtracted weight {} from current {}, overflowed" ,
141
- weight, this. current_weight,
142
- )
143
- } ) ;
133
+ this. global_weight . sub_weight ( weight) ;
144
134
return Poll :: Ready ( Some ( output) ) ;
145
135
}
146
136
Poll :: Ready ( None ) => { }
@@ -173,6 +163,9 @@ pub trait WeightedFuture: private::Sealed {
173
163
/// The associated `Future` type.
174
164
type Future : Future ;
175
165
166
+ /// The weight of the future.
167
+ fn weight ( & self ) -> usize ;
168
+
176
169
/// Turns self into its components.
177
170
fn into_components ( self ) -> ( usize , Self :: Future ) ;
178
171
}
@@ -189,6 +182,11 @@ where
189
182
{
190
183
type Future = Fut ;
191
184
185
+ #[ inline]
186
+ fn weight ( & self ) -> usize {
187
+ self . 0
188
+ }
189
+
192
190
#[ inline]
193
191
fn into_components ( self ) -> ( usize , Self :: Future ) {
194
192
self
0 commit comments