Implement From<T> for all Ts

Basically I have a question related to the topic of implicitly converting all the Err() into my error type.

Let's assume I am creating a crypto crate. As I understand it cryptographers are really paranoid about leaking internals, therefore I just have a struct CryptoError; which is the error type of the Result in this crate. Obviously I really don't care about implementing each implicit conversion manually, so the straight forward way would be:

impl<T> From<T> for CryptoError {
    fn from(_: T) -> Self {
        CryptoError
    }
}

This does not work and the reason given is:

note: conflicting implementation in crate `core`:
      - impl<T> From<T> for T;

Is there a way around that issue? Can I achieve that in another way?

The ring crate has a similar Unspecified error, and they just wrote the From impl for the specific types they need it for.

1 Like

Hmm yeah, thats always possible.

How does anyhow do it? Honestly I have never really used it and I am struggling to understand the code. But there is a statement in there:

impl<E> From<E> for Error
where
    E: StdError + Send + Sync + 'static,
{
    fn from(error: E) -> Self {
        let backtrace = backtrace_if_absent!(error);
        Error::from_std(error, backtrace)
    }
}

This seems roughly what I was trying to achieve, but I can't get that piece of code working for my error type...

I suppose, long-term / in the future a custom Result-like type (or in this case it’s actually more of an Option-like type) together with a Try implementation might constitute a nice solution. Not until the trait is stabilized, of course. See this playground for example.

1 Like

Anyhow implements conversion from types E: std::error::Error, but anyhow::Error does not implement the std::error::Error trait itself. This way, the overlap with the blanket From<T> for T implementation is avoided.

3 Likes

Ok there is a lot of thoughts I have:

  1. The version where I implement each conversion individually seems like the cleanest one, but I really fear that it is too much work and it will make the life difficult for everybody working on the project
  2. I really like the flexibility of the custom Try implementation. But it also feels wrong, because what I mean to express is a Result but I am using a different type.
  3. Not implementing Error for my type would probably work for me. This is not a public project, so I do not have to worry about the consumer of the library.
  4. Your analogy to an Option gave me an idea. Similarly to .ok() I could just implement a function like that:
trait EraseErr<T> {
    fn erase_err(self) -> Result<T, CryptoError>;
}

impl<T, E> EraseErr<T> for Result<T, E> {
    fn erase_err(self) -> Result<T, CryptoError> {
        self.map_err(|_| CryptoError)
    }
}