Repository: rust-lang/futures-rs (Rust)

Issue:
FuturesOrdered push_front does not work at the start
Running this code:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=30c5f139539ccf5dd237299c88b56a2e
```rust
use std::future::ready;
use std::collections::VecDeque;
use futures::stream::{FuturesOrdered, StreamExt};

#[tokio::main]
async fn main() {
    let mut set = VecDeque::new();

    set.push_back(2);  // should be the last
    set.push_front(1); // should be the second
    set.push_front(0);  // should be the first
    
    let x: Vec<i32> = set.into_iter().collect();
    assert_eq!(x, [0, 1, 2]);

    let mut set = FuturesOrdered::new();
    
    set.push_back(ready(2));  // should be the last
    set.push_front(ready(1)); // should be the second
    set.push_front(ready(0));  // should be the first
    
    let x: Vec<i32> = set.collect().await;
    assert_eq!(x, [0, 1, 2]);
}
```

You see the assertion on the VecDeque passes, but the same assertion through FuturesOrdered fails.

I noticed this working on my own implementation in https://github.com/conradludgate/futures-buffered - I found that turning the `usize` counters into `isize` fixes it with no noticeable downsides.


Discussion:

Patch:
diff --git a/futures-util/src/stream/futures_ordered.rs b/futures-util/src/stream/futures_ordered.rs
index f1c93fd68..b18d06626 100644
--- a/futures-util/src/stream/futures_ordered.rs
+++ b/futures-util/src/stream/futures_ordered.rs
@@ -19,7 +19,7 @@ pin_project! {
     struct OrderWrapper<T> {
         #[pin]
         data: T, // A future or a future's output
-        index: usize,
+        index: isize,
     }
 }
 
@@ -95,8 +95,8 @@ where
 pub struct FuturesOrdered<T: Future> {
     in_progress_queue: FuturesUnordered<OrderWrapper<T>>,
     queued_outputs: BinaryHeap<OrderWrapper<T::Output>>,
-    next_incoming_index: usize,
-    next_outgoing_index: usize,
+    next_incoming_index: isize,
+    next_outgoing_index: isize,
 }
 
 impl<T: Future> Unpin for FuturesOrdered<T> {}
@@ -160,13 +160,9 @@ impl<Fut: Future> FuturesOrdered<Fut> {
     /// task notifications. This future will be the next future to be returned
     /// complete.
     pub fn push_front(&mut self, future: Fut) {
-        if self.next_outgoing_index == 0 {
-            self.push_back(future)
-        } else {
-            let wrapped = OrderWrapper { data: future, index: self.next_outgoing_index - 1 };
-            self.next_outgoing_index -= 1;
-            self.in_progress_queue.push(wrapped);
-        }
+        let wrapped = OrderWrapper { data: future, index: self.next_outgoing_index - 1 };
+        self.next_outgoing_index -= 1;
+        self.in_progress_queue.push(wrapped);
     }
 }
 


Test patch:
diff --git a/futures/tests/stream_futures_ordered.rs b/futures/tests/stream_futures_ordered.rs
index 8b85a3365..5a4a3e22e 100644
--- a/futures/tests/stream_futures_ordered.rs
+++ b/futures/tests/stream_futures_ordered.rs
@@ -146,3 +146,27 @@ fn queue_never_unblocked() {
     assert!(stream.poll_next_unpin(cx).is_pending());
     assert!(stream.poll_next_unpin(cx).is_pending());
 }
+
+#[test]
+fn test_push_front_negative() {
+    let (a_tx, a_rx) = oneshot::channel::<i32>();
+    let (b_tx, b_rx) = oneshot::channel::<i32>();
+    let (c_tx, c_rx) = oneshot::channel::<i32>();
+
+    let mut stream = FuturesOrdered::new();
+
+    let mut cx = noop_context();
+
+    stream.push_front(a_rx);
+    stream.push_front(b_rx);
+    stream.push_front(c_rx);
+
+    a_tx.send(1).unwrap();
+    b_tx.send(2).unwrap();
+    c_tx.send(3).unwrap();
+
+    // These should all be recieved in reverse order
+    assert_eq!(Poll::Ready(Some(Ok(3))), stream.poll_next_unpin(&mut cx));
+    assert_eq!(Poll::Ready(Some(Ok(2))), stream.poll_next_unpin(&mut cx));
+    assert_eq!(Poll::Ready(Some(Ok(1))), stream.poll_next_unpin(&mut cx));
+}