Make error chain work with std::string::FromUtf8Error


#1

I am using String::from_utf8 in a function that I want to return Result using error-chain. However, this doesn’t work:

pub mod errors {
    error_chain!{
        foreign_links {
            Io(::std::io::Error);
            Utf8(::std::string::FromUtf8Error); // error: expected struct `errors::Error`, found struct `std::string::FromUtf8Error
        }
    }
}

The first one, Io is copied from the docs & works fine.


#2

Can you show the function where you’re trying to use it?


#3

I can only show some bits:

Here’s part of the caller:

fn get_data(which: &str, prefix: &str, what: &str) -> Result<KeyValues> {
    let output = Command::new("wmic").arg(&which).arg("get").arg(&what)
                                     .arg("/format:list").output()?;
    let text = string_for_bytes(output.stdout)?;
    ...

And here’s the function that could produce the error:

fn string_for_bytes(bytes: Vec<u8>) -> Result<String> {
    String::from_utf8(bytes.iter() // Effectively deletes non-ASCII chars
                      .map(|b| if *b > 0x7F { b' ' } else { *b })
                      .collect())
}

Thanks.


#4

You need to trigger an Into conversion. A simple way is to do this:

fn string_for_bytes(bytes: Vec<u8>) -> Result<String> {
    Ok(String::from_utf8(
        bytes
            .iter()
            .map(|b| if *b > 0x7F { b' ' } else { *b })
            .collect(),
    )?)
}

Or you can do:

fn string_for_bytes(bytes: Vec<u8>) -> errors::Result<String> {
    String::from_utf8(
        bytes
            .iter()
            .map(|b| if *b > 0x7F { b' ' } else { *b })
            .collect(),
    ).map_err(Into::into)
}

#5

Thanks, I used the first approach & it worked perfectly!