Async UdpStream: request for API feedback & code review
โ Rust ๐ 2026-04-26 ๐ค surdeus ๐๏ธ 2As part of a larger personal project, I needed (wanted?) a run-time agnostic, ergonomic wrapper around a non-blocking, non-exclusive, async UdpSocket.
I'd love your feedback to both the API and the code itself for UdpStream as defined here ssdp-rs/src/udp.rs ยท MusicalNinjaDad/splurt
The main API is
// construct by binding to a socket & specifying max expected
//length for incoming datagrams
let mut stream = UdpStream::<32>::bind(addr).expect("bound to socket");
// push to send
let msg: &[u8; 17] = b"udp loopback test";
stream.push(msg, rec_addr).await.expect("send msg");
// next to receive
let (msg, len, sent_by) = receiver
.next()
.await
.expect("a message")
.expect("a valid message");
(Don't worry about UdpConnectedStream, I'm intending to rework it or remove it later)
A more complete example from the tests:
#[futures_net::test]
async fn push_to_send() {
let loopback = Ipv4Addr::new(127, 0, 0, 1);
// analog https://doc.rust-lang.org/std/net/struct.TcpListener.html#method.bind
// Binding with a port number of 0 will request that the OS assigns a port to this listener.
// The port allocated can be queried via the TcpListener::local_addr method.
let addr: SocketAddr = SocketAddrV4::new(loopback, 0).into();
let mut receiver = UdpStream::<32>::bind(addr).expect("receiver");
let rec_addr = receiver.local_addr().expect("bound port");
dbg!(rec_addr);
let mut sender = UdpStream::<32>::bind(addr).expect("sender");
let send_addr = sender.local_addr().expect("bound port");
dbg!(send_addr);
let mut received: [u8; 17] = [b'\x00'; 17];
let msg: &[u8; 17] = b"udp loopback test";
let mut outer_sent_by = SocketAddr::from_str("8.8.8.8:80").expect("valid addr");
let send = async move {
println!("sending {}", String::from_utf8_lossy(msg));
sender.push(msg, rec_addr).await.expect("send msg");
};
let rec = async {
println!("initiating receiver");
let (msg, len, sent_by) = receiver
.next()
.await
.expect("a message")
.expect("a valid message");
println!(
"received: {} from {} ({} bytes)",
String::from_utf8_lossy(&msg),
sent_by,
len
);
received = msg[..len].try_into().expect("17 bytes in msg");
outer_sent_by = sent_by;
};
println!("ready to join");
futures::join!(rec, send);
assert_eq!(
String::from_utf8_lossy(&received),
String::from_utf8_lossy(msg)
);
assert_eq!(outer_sent_by, send_addr)
}
(and yes ... a real-world usage would handle the incoming information much more safely)
1 post - 1 participant
๐ท๏ธ Rust_feed