Generic implementation for associated type

I'm trying to write the following code:

pub enum Error<T> {
    Generic,
    Transport(T),
}

impl<T: Transport> Device<T> {
    pub fn new(t: T) -> Self {
        Self(t)
    }

    pub fn thing(&mut self) -> Result<(), Error<T::Error>> {
        self.0.transact(&[1, 2, 3], &mut [1, 2, 3])?; // <------------
        Ok(())
    }
}

pub trait Transport {
    type Error;

    fn transact(&mut self, command: &[u8], response: &mut [u8]) -> Result<(), Self::Error>;
}

But I'm unsure what my std::convert::From signature should look like to allow me to convert from T::Error to Error<T::Error> at the arrowed line above.

Should I be trying to implement std::convert::From in a generic way? Should I be adding a constraint to type Error inside Transport that makes implementers bring their own From?

I think there is no clear right or wrong answer here. Implementing From<T> for Error<T> generically is certainly an option. This of course won’t scale to a more complicated Error<T1, T2> with multiple variants like Transport. Another option to consider is also to just add .map_err(Error::Transport).

self.0.transact(&[1, 2, 3], &mut [1, 2, 3]).map_err(Error::Transport)?;

When choosing the explicit option, you can also (if you want) rewrite Error, to take the T: Transport argument, like

pub enum Error<T: Transport> {
    Generic,
    Transport(T::Error),
}

Which simplifies/shortens the signature of thing

pub fn thing(&mut self) -> Result<(), Error<T>>

Unfortunately, rustc sees some obscure impossible conflicts (with std’s impl From<T> for T) when you try to write an

impl<T: Transport> From<T::Error> for Error<T>

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.