rustasync-awaitrust-futures

How to get the result of the first future to complete in a collection of futures?


I have a bunch of async_std::UdpSocket and want to drive them all until the first one completes, then get the result from its corresponding u8 buffer.

I've tried

// build sockets and buffers
let sockets = Vec::new();
let buffers = HashMap::new();
for addr in ["127.0.0.1:4000", "10.0.0.1:8080", "192.168.0.1:9000"] {
    let socket = UdpSocket::bind(addr.parse().unwrap()).await?;
    let buf = [0u8; 1500];
    sockets.push(socket);
    buffers.insert(socket.peer_addr()?, buf);
}

// create an iterator of tasks reading from each socket
let socket_tasks = sockets.into_iter().map(|socket| {
    let socket_addr = socket.peer_addr().unwrap();
    let buf = buffers.get_mut(&socket_addr).unwrap();
    socket
        .recv_from(buf)
        .and_then(|_| async move { Ok(socket_addr) })
});

// wait for the first socket to return a value (DOESN'T WORK)
let buffer = try_join_all(socket_tasks)
    .and_then(|socket_addr| async { Ok(buffers.get(&socket_addr)) })
    .await

However this does not work because futures::future::try_join_all drives all futures to completion and returns a Vec<(SocketAddr)>. I want to get the result when a single future completes and get just a SocketAddr--something akin to select! but over a collection.

How can this be done?


Solution

  • If you only need the first future you can also use futures::future::select_all(). If there are many futures FuturesUnordered may be more performant because it only polls future when they awake, but if there are few select_all() is likely to be more performant as it is doing less work.