Accepting &T and AsRef<T> on the same function


#1

Hi

I’d like to have a function to which i can pass both a reference or something that can be converted to that reference cause it implements AsRef for that type. For example:

struct Color{
    r: f32, g: f32, b: f32
}

impl AsRef<[f32;3]>{
    fn as_ref() -> &[f32;3] {
        unsafe{ mem::transmute(self)
    }
}

fn draw<C:SomeTrait>(c: &C)>{
...

so draw could be called as:

draw(&Color{r:1., g:1., b:1.});

or

draw(&[1., 1., 1.]);

is there any way to write such a trait or any other way to get the draw function to accept both a reference to &[f32;3] or an AsRef<[f32;3]>

thanks


#2

You can implement Deref for Color and then use deref coercion. E.g.:

impl Deref for Color {
    type Target = [f32;3];
    
    fn deref(&self) -> &[f32;3] {
        unsafe{ mem::transmute(self)}
    }
}


fn draw(c: &[f32;3]) {
}


fn main() {
    draw(&Color{r:1., g:1., b:1.});

    draw(&[1., 2., 3.]);
}

#3

thanks, but i’d like to use this with types implemented on other’s libraries so implementing Deref or any other traits for the types is not an option.


#4

I see. So those other types will implement AsRef<[f32;3]> though?


#5

yes AsRef is usually implemented


#6

So apparently there’s no AsRef<[f32;3]> for &[f32;3] - not sure why. But, I got it to work by using Borrow instead of AsRef, although this probably doesn’t help you either since you mentioned the types implement AsRef:

impl Borrow<[f32;3]> for Color {

    fn borrow(&self) -> &[f32;3] {
        
        unsafe{ mem::transmute(self)}
}
}



fn draw<T:Borrow<[f32;3]>>(c: &T) {
}



fn main() {
    draw(&Color{r:1., g:1., b:1.});
    draw(&[1., 2., 3.]);
}

There’s a impl<'a, T> Borrow<T> for &'a T where T: ?Sized in the std, which is what I think makes the above work. I don’t see such a blanket impl for AsRef though.