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?
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.