genericsrustpolymorphismtraitsparametric-polymorphism

Making a generic From/Into shortcut for two-steps From


StructA implements From<StructB>, and StructB implements From<S>.

How can I generically implement a 'shortcut' Into<StructA> for S or From<S> for StructA?

If this is a bad idea, please do tell. But kindly explain how to do it anyway for the sake of learning.

Here's my attempt:

struct StructA {
    f: StructB
}

struct StructB {
    g: i32
}

impl From<StructB> for StructA {
    fn from(v: StructB) -> Self {
        Self {
            f: v
        }
    }
}

impl From<i32> for StructB {
    fn from(v: i32) -> Self {
        Self {
            g: v
        }
    }
}

impl<T: Into<StructA>, S: Into<T>> Into<StructA> for S {
    fn into(self) -> StructA {
        let i: T = self.into();
        i.into()
    }
}

The error I get is the type parameter 'T' is not constrained by the impl trait, self type, or predicates.

I don't understand it. Isn't T constrained by Into<StructA>?


Solution

  • The error message basically states that the compiler has no way to infer what type T may be – it basically has to figure out whether any type T exists such that the given trait bounds T: Into<StructA>, S: Into<T> are satisfied, and this is not possible in Rust. One problem with this is, as stated in the comments, that there might be multiple types T satisfying the trait bounds, in which case the compiler can't determine which one to use.

    In addition, the Into trait already has a blanket implementation in the standard library.

    impl<T, U: From<T>> Into<U> for T;
    

    There is no way for the compiler to guarantee that this impl doesn't overlap with your blanket impl, which would also make the implementation ambiguous.

    I recommend you simply implement From<i32> for StructA explicitly. If you need many such implementations, macros could be useful.