Is it possible to impl `From<Wrapper<T>>` for `Wrapper<U>`?

For context, I'm working on a pet project that includes a Span type that annotates a value with a start and end in some input:

struct Span<T> {
    start: usize,
    end: usize,
    value: T
}

This Span is used to wrap errors (e.g. Result<_, Span<E>>), which I would like to be compatible with ? coercion. In order for this to work, I think I need to implement:

impl<T, U> From<Span<T>> for Span<U>
where
    U: From<T>
{
    fn from(span: Span<T>) -> Self {
        Span {
            start: span.start,
            end: span.end,
            value: U::from(span.value)
        }
    }
}

This fails with:

conflicting implementations of trait `std::convert::From<span::Span<_>>` for type `span::Span<_>`

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

I understand what this means, and suspect that I am out of luck. However I'm struggling to find out definitively whether it's possible to specify that T and U must be different and therefore avoid the conflict.

If not, this doesn't seem like an unintuitive use-case, so perhaps someone knows of another approach that could solve the use-case of propagating wrapper types through ? coercion?

No, sorry, it's not possible to make an exception for U = T.

I recommend you to implement .map() method instead of From trait (as Option<T> and Result<T, E> do).
Then v.map(Into::into) allows you to convert v: Span<T> into Span<U>.

EDIT:
Sorry I overlooked Result<_, Span<E>> use case...
I don't think it's possible to use ? to convert Span<T> into Span<U>.
Extension trait will be useful to add an extension method to Result<T, Span<E>> which converts self into Result<T, Span<U>>.

Thanks for your responses! I was afraid of that, oh well.

In the end I did similar to your suggestion @nop_thread – I already had a map function on Span, and can combine that with Result::map_err for a reasonable experience:

fn foo<E: From<Error>>() -> Result<Value, E> {
  let value = expression().map_err(|span| span.map(E::from))?;
  Ok(value)
}

I also have an extension trait already, so it's a good shout to add a map_err_span or something that would let me write:

fn foo<E: From<Error>>() -> Result<Value, E> {
  let value = expression().map_err_span(E::from)?;
  Ok(value)
}

Thanks again.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.