Skip to content

Commit 48d65c3

Browse files
ibraheemdevtaiki-e
authored andcommitted
add FuturesUnordered::into_iter, make iter_pin_ref public (#2423)
1 parent aa39d14 commit 48d65c3

File tree

4 files changed

+134
-3
lines changed

4 files changed

+134
-3
lines changed

futures-util/src/stream/futures_unordered/iter.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,55 @@ pub struct IterPinRef<'a, Fut> {
2929
/// Immutable iterator over all the futures in the unordered set.
3030
pub struct Iter<'a, Fut: Unpin>(pub(super) IterPinRef<'a, Fut>);
3131

32+
#[derive(Debug)]
33+
/// Owned iterator over all futures in the unordered set.
34+
pub struct IntoIter<Fut: Unpin> {
35+
pub(super) len: usize,
36+
pub(super) inner: FuturesUnordered<Fut>,
37+
}
38+
39+
impl<Fut: Unpin> Iterator for IntoIter<Fut> {
40+
type Item = Fut;
41+
42+
fn next(&mut self) -> Option<Fut> {
43+
// `head_all` can be accessed directly and we don't need to spin on
44+
// `Task::next_all` since we have exclusive access to the set.
45+
let task = self.inner.head_all.get_mut();
46+
47+
if (*task).is_null() {
48+
return None;
49+
}
50+
51+
unsafe {
52+
// Moving out of the future is safe because it is `Unpin`
53+
let future = (*(**task).future.get()).take().unwrap();
54+
55+
// Mutable access to a previously shared `FuturesUnordered` implies
56+
// that the other threads already released the object before the
57+
// current thread acquired it, so relaxed ordering can be used and
58+
// valid `next_all` checks can be skipped.
59+
let next = (**task).next_all.load(Relaxed);
60+
*task = next;
61+
self.len -= 1;
62+
Some(future)
63+
}
64+
}
65+
66+
fn size_hint(&self) -> (usize, Option<usize>) {
67+
(self.len, Some(self.len))
68+
}
69+
}
70+
71+
impl<Fut: Unpin> ExactSizeIterator for IntoIter<Fut> {}
72+
3273
impl<'a, Fut> Iterator for IterPinMut<'a, Fut> {
3374
type Item = Pin<&'a mut Fut>;
3475

3576
fn next(&mut self) -> Option<Pin<&'a mut Fut>> {
3677
if self.task.is_null() {
3778
return None;
3879
}
80+
3981
unsafe {
4082
let future = (*(*self.task).future.get()).as_mut().unwrap();
4183

@@ -78,6 +120,7 @@ impl<'a, Fut> Iterator for IterPinRef<'a, Fut> {
78120
if self.task.is_null() {
79121
return None;
80122
}
123+
81124
unsafe {
82125
let future = (*(*self.task).future.get()).as_ref().unwrap();
83126

@@ -120,3 +163,6 @@ unsafe impl<Fut: Sync> Sync for IterPinRef<'_, Fut> {}
120163

121164
unsafe impl<Fut: Send> Send for IterPinMut<'_, Fut> {}
122165
unsafe impl<Fut: Sync> Sync for IterPinMut<'_, Fut> {}
166+
167+
unsafe impl<Fut: Send + Unpin> Send for IntoIter<Fut> {}
168+
unsafe impl<Fut: Sync + Unpin> Sync for IntoIter<Fut> {}

futures-util/src/stream/futures_unordered/mod.rs

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use futures_task::{FutureObj, LocalFutureObj, LocalSpawn, Spawn, SpawnError};
2222
mod abort;
2323

2424
mod iter;
25-
pub use self::iter::{Iter, IterMut, IterPinMut, IterPinRef};
25+
pub use self::iter::{IntoIter, Iter, IterMut, IterPinMut, IterPinRef};
2626

2727
mod task;
2828
use self::task::Task;
@@ -194,10 +194,11 @@ impl<Fut> FuturesUnordered<Fut> {
194194
}
195195

196196
/// Returns an iterator that allows inspecting each future in the set.
197-
fn iter_pin_ref(self: Pin<&Self>) -> IterPinRef<'_, Fut> {
197+
pub fn iter_pin_ref(self: Pin<&Self>) -> IterPinRef<'_, Fut> {
198198
let (task, len) = self.atomic_load_head_and_len_all();
199+
let pending_next_all = self.pending_next_all();
199200

200-
IterPinRef { task, len, pending_next_all: self.pending_next_all(), _marker: PhantomData }
201+
IterPinRef { task, len, pending_next_all, _marker: PhantomData }
201202
}
202203

203204
/// Returns an iterator that allows modifying each future in the set.
@@ -581,6 +582,38 @@ impl<Fut> Drop for FuturesUnordered<Fut> {
581582
}
582583
}
583584

585+
impl<'a, Fut: Unpin> IntoIterator for &'a FuturesUnordered<Fut> {
586+
type Item = &'a Fut;
587+
type IntoIter = Iter<'a, Fut>;
588+
589+
fn into_iter(self) -> Self::IntoIter {
590+
self.iter()
591+
}
592+
}
593+
594+
impl<'a, Fut: Unpin> IntoIterator for &'a mut FuturesUnordered<Fut> {
595+
type Item = &'a mut Fut;
596+
type IntoIter = IterMut<'a, Fut>;
597+
598+
fn into_iter(self) -> Self::IntoIter {
599+
self.iter_mut()
600+
}
601+
}
602+
603+
impl<Fut: Unpin> IntoIterator for FuturesUnordered<Fut> {
604+
type Item = Fut;
605+
type IntoIter = IntoIter<Fut>;
606+
607+
fn into_iter(mut self) -> Self::IntoIter {
608+
// `head_all` can be accessed directly and we don't need to spin on
609+
// `Task::next_all` since we have exclusive access to the set.
610+
let task = *self.head_all.get_mut();
611+
let len = if task.is_null() { 0 } else { unsafe { *(*task).len_all.get() } };
612+
613+
IntoIter { len, inner: self }
614+
}
615+
}
616+
584617
impl<Fut> FromIterator<Fut> for FuturesUnordered<Fut> {
585618
fn from_iter<I>(iter: I) -> Self
586619
where

futures/tests/auto_traits.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1827,6 +1827,13 @@ pub mod stream {
18271827
assert_impl!(futures_unordered::IterPinRef<()>: Sync);
18281828
assert_not_impl!(futures_unordered::IterPinRef<*const ()>: Sync);
18291829
assert_impl!(futures_unordered::IterPinRef<PhantomPinned>: Unpin);
1830+
1831+
assert_impl!(futures_unordered::IntoIter<()>: Send);
1832+
assert_not_impl!(futures_unordered::IntoIter<*const ()>: Send);
1833+
assert_impl!(futures_unordered::IntoIter<()>: Sync);
1834+
assert_not_impl!(futures_unordered::IntoIter<*const ()>: Sync);
1835+
// The definition of futures_unordered::IntoIter has `Fut: Unpin` bounds.
1836+
// assert_not_impl!(futures_unordered::IntoIter<PhantomPinned>: Unpin);
18301837
}
18311838

18321839
/// Assert Send/Sync/Unpin for all public types in `futures::task`.

futures/tests/stream_futures_unordered.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,51 @@ fn iter_len() {
214214
assert!(iter.next().is_none());
215215
}
216216

217+
#[test]
218+
fn into_iter_cancel() {
219+
let (a_tx, a_rx) = oneshot::channel::<i32>();
220+
let (b_tx, b_rx) = oneshot::channel::<i32>();
221+
let (c_tx, c_rx) = oneshot::channel::<i32>();
222+
223+
let stream = vec![a_rx, b_rx, c_rx].into_iter().collect::<FuturesUnordered<_>>();
224+
225+
let stream = stream
226+
.into_iter()
227+
.map(|mut rx| {
228+
rx.close();
229+
rx
230+
})
231+
.collect::<FuturesUnordered<_>>();
232+
233+
let mut iter = block_on_stream(stream);
234+
235+
assert!(a_tx.is_canceled());
236+
assert!(b_tx.is_canceled());
237+
assert!(c_tx.is_canceled());
238+
239+
assert_eq!(iter.next(), Some(Err(futures::channel::oneshot::Canceled)));
240+
assert_eq!(iter.next(), Some(Err(futures::channel::oneshot::Canceled)));
241+
assert_eq!(iter.next(), Some(Err(futures::channel::oneshot::Canceled)));
242+
assert_eq!(iter.next(), None);
243+
}
244+
245+
#[test]
246+
fn into_iter_len() {
247+
let stream = vec![future::pending::<()>(), future::pending::<()>(), future::pending::<()>()]
248+
.into_iter()
249+
.collect::<FuturesUnordered<_>>();
250+
251+
let mut into_iter = stream.into_iter();
252+
assert_eq!(into_iter.len(), 3);
253+
assert!(into_iter.next().is_some());
254+
assert_eq!(into_iter.len(), 2);
255+
assert!(into_iter.next().is_some());
256+
assert_eq!(into_iter.len(), 1);
257+
assert!(into_iter.next().is_some());
258+
assert_eq!(into_iter.len(), 0);
259+
assert!(into_iter.next().is_none());
260+
}
261+
217262
#[test]
218263
fn futures_not_moved_after_poll() {
219264
// Future that will be ready after being polled twice,

0 commit comments

Comments
 (0)