Search code examples
rusttraits

Extend TryFrom to use a generic error type


I am attempting to use TryFrom to convert types, except that I would like to use a generic error type. How can I extend TryFrom to cope with an additional generic error parameter?

use core::convert::TryFrom;

enum MyError<E> {
    UnexpectedValue,
    SomeGeneric(E),
}

enum MyEnum {
    Zero,
    One,
    Two,
}

impl TryFrom<u32> for MyEnum {
    type Error = MyError<E>;
    fn try_from(value: u32) -> Result<Self, Self::Error> {
        match value {
            0 => Ok(MyEnum::Zero),
            1 => Ok(MyEnum::One),
            2 => Ok(MyEnum::Two),
            _ => Err(MyError::UnexpectedValue),
        }
    }
}

I wondered if I could extend TryFrom into a new trait which incorporates a generic error parameter, but I'm not sure how to go about doing that.


Solution

  • The associated Error type of TryFrom is not generic and introducing a generic E (i.e. impl<E> TryFrom<u32> for MyEnum) would be unconstrained, so you cannot do this.

    Likely your best route would be to create a distinct error type for your conversion with a From implementation that can convert it to your desired error type. That way, a ? might convert transparently or you'd use .map_err(MyError::<_>::from) if it doesn't.

    Demonstration:

    struct UnexpectedMyEnumValue;
    
    impl<E> From<UnexpectedMyEnumValue> for MyError<E> {
        fn from(err: UnexpectedMyEnumValue) -> MyError<E> {
            MyError::UnexpectedValue
        }
    }
    
    impl TryFrom<u32> for MyEnum {
        type Error = UnexpectedMyEnumValue;
        fn try_from(value: u32) -> Result<Self, Self::Error> {
            match value {
                0 => Ok(MyEnum::Zero),
                1 => Ok(MyEnum::One),
                2 => Ok(MyEnum::Two),
                _ => Err(UnexpectedMyEnumValue),
            }
        }
    }
    
    fn f() -> Result<(), MyError<()>> {
        let _e = MyEnum::try_from(5)?; // converts to MyError automatically
        Ok(())
    }