Limit set of types instanced as generic param

Hi, I'm trying to define a custom Error that, much like anyhow, can have context attached.
Unlike anyhow, I want the custom Error to only accept a limited set of Errors from other domains.

An impl From<E> for each other Error E satisfies the case where I simply want to convert other Error's to the CustomError.

struct CustomError {
    ...
}

impl StdError for CustomError {};

impl From<lib_a::Error> for CustomError {
    fn from(e: lib_a::Error) -> Self {
        CustomError { ... }
    }
} 

impl From<lib_b::Error> for CustomError {
    fn from(e: lib_b::Error) -> Self {
        CustomError { ... }
    }
} 

But if I want to add context to the Error using an anyhow style extension trait and restrict the set of types that can be converted to CustomError things get a bit more complicated.

let url: Url = "localhost".parse().context("Parsing a URL failed")?;

My attempt at an implementation is:

trait Context {
    fn context(self, s: String) -> CustomError;
}

impl<T> Context for StdResult<T, lib_a::Error> {
    fn context(self, s: String) -> StdResult<T, CustomError> {
        todo!("Perform a specific lib_a::Error action");
    }
}

impl<T> Context for StdResult<T, lib_b::Error> {
    fn context(self, s: String) -> StdResult<T, CustomError> {
        todo!("Perform a specific lib_b::Error action");
    }
}

But this results in requiring type annotations at the call site due to conflicting impls.

error[E0283]: type annotations needed
   --> ext_api/src/event.rs:174:10
    |
174 |         .context("Parsing a URL failed")?;
    |          ^^^^^^^^^^^
    |
note: multiple `impl`s satisfying `std::result::Result<_, _>: 
...

Does anyone have any ideas on how I can limit the set of Errors that are allowed to have context?

Thanks

This should be fine, you just need to have context take self and move the type to parse.

let url = "localhost".parse::<Url>().context("Parsing a URL failed")?;

context also needs to return StdResult<T, CustomError>

I figured out a solution. I just need to make a single impl of Context and call one of the many, non-conflicting impl From's.

impl<T,  E> Context for StdResult<T, E>
where
    E: StdError + Send + Sync + 'static,
    CustomError: From<E>
{
    fn context(self, s: String) -> StdResult<T, CustomError> {
        match self {
            Ok(v) => Ok(v),
            Err(e) => Err(Into::<CustomError>::into(e))
        }
    }
}

I fixed up the example code. I typed it out quickly from memory.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.