user1096614
user1096614

Reputation:

Reuse the description of an existing Error when creating a new Error

I have the following code in Rust, which does not compile, but shows the intent of what I'd like to do.

    pub fn parse(cursor: &mut io::Cursor<&[u8]>) -> io::Result<Ack> {
        use self::byteorder::{BigEndian, ReadBytesExt};
        use self::core::error::Error;

        match cursor.read_u16::<BigEndian>() {
            Err(byteorder::Error::Io(error)) => Err(error),
            Err(error) =>
                Err(io::Error::new(io::ErrorKind::Other, error.description(),
                                   None)),
            Ok(value) => Ok(Ack { block_number: value })
        }
    }

Essentially, I want to take the error description of an error returned by the byteorder library and use it to create the description of an error I'll pass back to the user of my library. This fails with packets.rs:166:58: 166:63 error:errordoes not live long enough, and I understand why.

The byteorder library solves this issue by wrapping an std::io::Result in the byteorder::Error::Io constructor. However, I don't want to take this route because I'd have to define my own error type that wraps either an std::io::Error or a byteorder::Error. It seems to me that my users shouldn't know or care that I use the byteorder library, and it shouldn't be part of my interface.

I'm a Rust newbie and don't yet know the idioms and best practices of the language and design. What are my options for dealing with this?

Upvotes: 4

Views: 251

Answers (2)

Vladimir Matveev
Vladimir Matveev

Reputation: 128161

Your problem is in fact in that io::Error::new()'s second parameter is &'static str, while byteorder::Error::description() returns a &'a str where 'a is lifetime of the error object itself which is less than 'static. Hence you can't use it for io::Error's description.

The simplest fix would be moving byteorder::Error description to detail field of io::Error:

Err(error) =>
    Err(io::Error::new(
        io::ErrorKind::Other,
        "byteorder error",
        Some(error.description().to_string())
    )),

However, you should seriously consider making a custom wrapper error type which encapsulates all "downstream" errors. With properly written FromError instances you should be able to write something like

try!(cursor.read_u16::<BigEndian>()
    .map(|value| Ack { block_number: value }))

instead of your whole match. Custom error wrappers will also help you when your program grows and more "downstream" error sources appear - you could just add new enum variants and/or FromError implementations to support these new errors.

Upvotes: 1

tafia
tafia

Reputation: 1562

I cannot test your code so I can't be sure. Isn't the ref keyword enough?

Err(byteorder::Error::Io(ref error)) => Err(error),

Upvotes: 0

Related Questions