Result<Option<Result<Message, WsError>>, Elapsed>
That’s three independent “not the happy path” channels: timeout, stream closed,
and websocket error.The nicer version is not a cleverer match. It’s choosing a domain error shape and converting into it one layer at a time:
let timed = tokio::time::timeout(duration, receiver.next()).await;
let next = timed.map_err(|_| ReceiveError::Timeout)?;
let item = next.ok_or(ReceiveError::Closed)?;
let msg = item.map_err(ReceiveError::WebSocket)?;
The ugly line is what happens when you have not decided where to normalize the
shape yet.a) Vibe coding produces bad code
b) Rust is weird
Somehow we’re supposed to accept b as the answer? Give me a break….