diff --git a/futures-util/src/stream/futures_unordered/iter.rs b/futures-util/src/stream/futures_unordered/iter.rs index ef7b15aed8..17cde4fac4 100644 --- a/futures-util/src/stream/futures_unordered/iter.rs +++ b/futures-util/src/stream/futures_unordered/iter.rs @@ -1,5 +1,5 @@ -use super::FuturesUnordered; use super::task::Task; +use super::FuturesUnordered; use core::marker::PhantomData; use core::pin::Pin; use core::sync::atomic::Ordering::Relaxed; @@ -9,12 +9,12 @@ use core::sync::atomic::Ordering::Relaxed; pub struct IterPinMut<'a, Fut> { pub(super) task: *const Task, pub(super) len: usize, - pub(super) _marker: PhantomData<&'a mut FuturesUnordered> + pub(super) _marker: PhantomData<&'a mut FuturesUnordered>, } #[derive(Debug)] /// Mutable iterator over all futures in the unordered set. -pub struct IterMut<'a, Fut: Unpin> (pub(super) IterPinMut<'a, Fut>); +pub struct IterMut<'a, Fut: Unpin>(pub(super) IterPinMut<'a, Fut>); #[derive(Debug)] /// Immutable iterator over all futures in the unordered set. @@ -22,12 +22,12 @@ pub struct IterPinRef<'a, Fut> { pub(super) task: *const Task, pub(super) len: usize, pub(super) pending_next_all: *mut Task, - pub(super) _marker: PhantomData<&'a FuturesUnordered> + pub(super) _marker: PhantomData<&'a FuturesUnordered>, } #[derive(Debug)] /// Immutable iterator over all the futures in the unordered set. -pub struct Iter<'a, Fut: Unpin> (pub(super) IterPinRef<'a, Fut>); +pub struct Iter<'a, Fut: Unpin>(pub(super) IterPinRef<'a, Fut>); impl<'a, Fut> Iterator for IterPinMut<'a, Fut> { type Item = Pin<&'a mut Fut>; @@ -85,10 +85,7 @@ impl<'a, Fut> Iterator for IterPinRef<'a, Fut> { // `head_all` was initially read for this iterator implies acquire // ordering for all previously inserted nodes (and we don't need to // read `len_all` again for any other nodes). - let next = (*self.task).spin_next_all( - self.pending_next_all, - Relaxed, - ); + let next = (*self.task).spin_next_all(self.pending_next_all, Relaxed); self.task = next; self.len -= 1; Some(Pin::new_unchecked(future)) @@ -115,3 +112,11 @@ impl<'a, Fut: Unpin> Iterator for Iter<'a, Fut> { } impl ExactSizeIterator for Iter<'_, Fut> {} + +// SAFETY: we do nothing thread-local and there is no interior mutability, +// so the usual structural `Send`/`Sync` apply. +unsafe impl Send for IterPinRef<'_, Fut> {} +unsafe impl Sync for IterPinRef<'_, Fut> {} + +unsafe impl Send for IterPinMut<'_, Fut> {} +unsafe impl Sync for IterPinMut<'_, Fut> {} diff --git a/futures/tests/auto_traits.rs b/futures/tests/auto_traits.rs index 935cf6a50f..3b4a755f8b 100644 --- a/futures/tests/auto_traits.rs +++ b/futures/tests/auto_traits.rs @@ -1780,24 +1780,24 @@ pub mod stream { assert_not_impl!(Zip: Unpin); assert_not_impl!(Zip: Unpin); - assert_not_impl!(futures_unordered::Iter<()>: Send); - assert_not_impl!(futures_unordered::Iter<()>: Sync); + assert_impl!(futures_unordered::Iter<()>: Send); + assert_impl!(futures_unordered::Iter<()>: Sync); assert_impl!(futures_unordered::Iter<()>: Unpin); // futures_unordered::Iter requires `Fut: Unpin` // assert_not_impl!(futures_unordered::Iter: Unpin); - assert_not_impl!(futures_unordered::IterMut<()>: Send); - assert_not_impl!(futures_unordered::IterMut<()>: Sync); + assert_impl!(futures_unordered::IterMut<()>: Send); + assert_impl!(futures_unordered::IterMut<()>: Sync); assert_impl!(futures_unordered::IterMut<()>: Unpin); // futures_unordered::IterMut requires `Fut: Unpin` // assert_not_impl!(futures_unordered::IterMut: Unpin); - assert_not_impl!(futures_unordered::IterPinMut<()>: Send); - assert_not_impl!(futures_unordered::IterPinMut<()>: Sync); + assert_impl!(futures_unordered::IterPinMut<()>: Send); + assert_impl!(futures_unordered::IterPinMut<()>: Sync); assert_impl!(futures_unordered::IterPinMut: Unpin); - assert_not_impl!(futures_unordered::IterPinRef<()>: Send); - assert_not_impl!(futures_unordered::IterPinRef<()>: Sync); + assert_impl!(futures_unordered::IterPinRef<()>: Send); + assert_impl!(futures_unordered::IterPinRef<()>: Sync); assert_impl!(futures_unordered::IterPinRef: Unpin); }