-1

I have the following implementation block which isn't very readable.

impl Xbee {
    async fn new(xbee_ip: Ipv4Addr) -> Result<Self, std::io::Error> {
        match tokio::net::UdpSocket::bind((Ipv4Addr::UNSPECIFIED, 0)).await
            .map(|socket| async {
                match socket.connect((xbee_ip, 3054)).await {
                    Ok(_) => Ok(Xbee {
                        ip: xbee_ip,
                        socket: socket,
                        last_seen: SystemTime::now(),
                    }),
                    Err(error) => Err(error)
                }
            }) {
                Ok(xbee) => xbee.await,
                Err(err) => Err(err),
        }
    }
}

As a start, I would like to remove the outermost match statement which is just there to await the future inside a result before putting it back into a result. It seems like this would be a good candidate for Result::{and_then, map, map_or, map_or_else} etc., however, I don't think any of these will work since the await would end up being inside an async closure which in turn, would need to be awaited. Is it possible to await the future inside a result without a match statement?

mallwright
  • 1,670
  • 14
  • 31
  • Since you managed to create a `Result, ...>` instead of an `impl Future>`, the answer is no, you cannot. However, if you fix your code, you can apply the shorthand `?` operator. – msrd0 Oct 06 '20 at 15:27
  • Could you elaborate in an answer what creating a `impl Future>` would look like and how that would solve the problem? – mallwright Oct 06 '20 at 15:33
  • It can look like `async { Ok(()) }` and can be accessed like `x.await?` instead of `match x { Ok(x) => x.await, Err(e) => return Err(e) }`. In fact, `impl Future>` would be the return type of your tokio methods, but your application of `.map` made it so that you placed the future inside the result instead of the result inside the future – msrd0 Oct 06 '20 at 15:39

1 Answers1

1

This does not answer the question above, however, by using the ? operator correctly, it is possible to make the above code much more readable by not having the future inside the result in the first place. Refactored code:

impl Xbee {
    async fn new(xbee_ip: Ipv4Addr) -> Result<Self, std::io::Error> {
        let socket = tokio::net::UdpSocket::bind((Ipv4Addr::UNSPECIFIED, 0)).await?;
        socket.connect((xbee_ip, 3054)).await?;
        let xbee = Xbee {
            ip: xbee_ip,
            socket: socket,
            last_seen: SystemTime::now(),
        };
        Ok(xbee)
    }
}
mallwright
  • 1,670
  • 14
  • 31
  • 1
    This doesn't actually answer your own question besides saying _just don't do it_ – msrd0 Oct 06 '20 at 15:29
  • I partially agree and would not accept it for this reason. However, I think it is still useful for others though who, like me, have over looked this simple work around. – mallwright Oct 06 '20 at 15:35
  • @msrd0 I have edited this answer to make it clear that this is not an answer to the question asked, but rather a work around – mallwright Oct 06 '20 at 15:39