Strange error case

use anyhow::{anyhow, Error};
use hex;
use base64;
use ascii85;

fn parse_binary(s: &str, encoding: &str) -> Result<Vec::<u8>, Error> {
    ...
    Ok(match encoding.as_str() {
        "base64" => base64::decode(s)?,
        "base16" => hex::decode(s)?,
        "base85" => ascii85::decode(&s)?,
        _ => return Err(anyhow!("Unknown binary encoding: {}", encoding))
    })

One of these is not like the others.

Base64 decode and hex decode compile fine. But "base85" generates these errors:

error[E0277]: the size for values of type `dyn std::error::Error` cannot be known at compilation time
   --> src/xml.rs:308:40
    |
308 |         "base85" => ascii85::decode(&s)?,
    |                                        ^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `dyn std::error::Error`
    = note: required because of the requirements on the impl of `std::error::Error` for `Box<dyn std::error::Error>`
    = note: required because of the requirements on the impl of `From<Box<dyn std::error::Error>>` for `anyhow::Error`
    = note: required by `from`

error[E0277]: `dyn std::error::Error` cannot be sent between threads safely
   --> src/xml.rs:308:40
    |
308 |         "base85" => ascii85::decode(&s)?,
    |                                        ^ `dyn std::error::Error` cannot be sent between threads safely
    |
    = help: the trait `Send` is not implemented for `dyn std::error::Error`
    = note: required because of the requirements on the impl of `Send` for `Unique<dyn std::error::Error>`
    = note: required because it appears within the type `Box<dyn std::error::Error>`
    = note: required because of the requirements on the impl of `From<Box<dyn std::error::Error>>` for `anyhow::Error`
    = note: required by `from`

error[E0277]: `dyn std::error::Error` cannot be shared between threads safely
   --> src/xml.rs:308:40
    |
308 |         "base85" => ascii85::decode(&s)?,
    |                                        ^ `dyn std::error::Error` cannot be shared between threads safely
    |
    = help: the trait `Sync` is not implemented for `dyn std::error::Error`
    = note: required because of the requirements on the impl of `Sync` for `Unique<dyn std::error::Error>`
    = note: required because it appears within the type `Box<dyn std::error::Error>`
    = note: required because of the requirements on the impl of `From<Box<dyn std::error::Error>>` for `anyhow::Error`
    = note: required by `from`

error: aborting due to 3 previous errors

The definition of base85's "decode" is:

pub fn decode(input: &str) -> Result<Vec<u8>, Box<dyn Error>>

The Box<dyn Error> will not convert to anyhow::error, obviously. But how did "Send" get into this? What's the right way to handle this error?

What happens if you remove the '&'? (To be like the others.)

No change.

ascii85 made the really unfortunate decision to use Box<dyn Error> as the return type of decode. The reason why Send is here is because anyhow::Error requires Send + Sync. This is because anyhow handles the common case, where this is true. You'll need to use Box<dyn Error> yourself instead of anyhow. Or you can try and get ascii85 to do proper error handling.

Oh, anyhow! wants Send. OK.

Workaround:

"base85" => match ascii85::decode(s) {Ok(v) => v, Err(e) => return Err(anyhow!("Base 85 decode error: {:?}",e))},

This match can be simplified to map_err method.

1 Like