Idiomatic From implementation with minimal code?

I want to be able to create a UserProtoBuf from a User, &User, or &mut User.

Currently all I need to create a UserProtoBuf is a &User. So I've implemented impl From<&User> for UserProtoBuf like this:

struct User {
    age: usize,
}

struct UserProtoBuf {
    age: usize,
}

impl From<&User> for UserProtoBuf {
    fn from(user: &User) -> Self {
        UserProtoBuf {
            age: user.age
        }
    }
}

And then when I need a UserProtoBuf I do this:

fn from_user(user: User) -> UserProtoBuf {
    (&user).into()
}

fn from_user_ref(user: &User) -> UserProtoBuf {
    user.into()
}

fn from_user_mut_ref(user: &mut User) -> UserProtoBuf {
    (&*user).into()
}

It works, but I'm wondering if there's anyway I can do better? In particular the calls to (&user).into() and (&*user).into() seem a bit odd. Is there some way to implement the From trait so that those special cases go away and I can just always do user.into() to get a UserProtoBuf?

You need to implement From for all the cases of User, &User and &mut User for the converted type then into with type specification will handle it like this.

1 Like

You can do one blanket impl to cover all 3:

impl<T> From<T> for UserProtoBuf 
where T: std::borrow::Borrow<User>
{
    fn from(user: T) -> Self {
        UserProtoBuf {
            age: user.borrow().age
        }
    }
}
7 Likes

Ahh, that's what I was wanting to do. Thanks!

Finally I learned what Borrow does :sweat_smile: