How to implement From<AsRef<[U]>> for generic U?

Hi, I am trying to create a trait that marks some built-in types as valid for consumption for a Struct via slices, but I am unable to produce the right "From". Any ideas how to make below compile?

trait Bla: Sized {}

impl Bla for u32 {}

struct A {}

impl<U: Bla, T: AsRef<[U]>> From<T> for A {
    fn from(_p: T) -> Self {
        Self {}
    }
}

fn main() {
    A::from(&[1u32]);
}

The problem is that you could have two types B and C that both implement Bla and a type D that implements both AsRef<[B]> and AsRef<[C]>. At this point your implementation of From<D> for A is defined twice, one with U=B and one with U=C.

As an example, if what you want would be allowed, what should this code print?

3 Likes

Thanks a lot @SkiFire13 for the explanation, it makes total sense. Maybe then I do not need all of them. I was just trying to cover 3 cases:

fn main() {
    A::from(&[1u32]);
    A::from(&[1u32, 2u32]);
    A::from(&vec![1u32, 2u32]);
}

in a single implementation. Isn't that what AsRef is useful for?

Usually you would use AsRef for things like this, however it just can't work when you don't have a concrete type to use as argument for AsRef but instead you want to just costrain it.

1 Like

I would just make it a generic constructor:

impl A {
    fn from_bla_slice<U: Bla, T: AsRef<[U]>>(_p: T) -> Self {
        Self {}
    }
}

This way if there's an ambiguity (unlikely) you can resolve it at the call site with an annotation like A::from_bla_slice::<u32, _>(vec![17]), rather than being blocked by the coherence rules.

ETA: also this constructor should almost certainly take &T, not T.

2 Likes