Cheap array reference reshaping

I'd like to create safe functions that reshape array references & possibly arrays themselves.
This can be useful for reinterpretation of array dimensions without cloning the content.
Here my_reshape uses unsafe memory function as I haven't found any alternative.

    unsafe fn my_reshape(arr_ref: &[u32; 4])-> &[[u32; 2]; 2]{
        std::mem::transmute(arr_ref)
    }

    let arr= [1,2,3,4];
    let arr_ref= &arr;
    let reshaped_arr_ref= unsafe{ my_reshape(arr_ref) };

    assert_eq!( reshaped_arr_ref, &[[1,2],[3,4]] );

This is not, in general, possible safely. The generally recommended approach is to use the bytemuck crate for at least encapsulating and abstracting away most of the unsafety.


By the way, never transmute references. I don't know where this is coming from, because I've seen a lot of reference transmuting posts recently, but it's almost never sound, and almost never what you want. Transmutation is not transitive, so T -> U being fine doesn't imply &T -> &U being OK (nor the other way around). Furthermore, pointers/references aren't even guaranteed to have a single, well-specified layout, so this can easily end up being UB.

If you want to convert between references of different types, you can go through raw pointers and cast (using as or the .cast() method).

2 Likes

Although I agree that pointer casts are almost always the way to go, "almost never sound" is a bit strong here. If T and U are both Sized, then &T -> &U via transmutation is no less sound than &T -> *const T -> *const U -> &U, since all thin references and pointers are specified to have the same representation. The main footgun is transmuting &T -> &U where T: !Sized and U: !Sized, which is unsound due to the fat pointer layout being unspecified. It's still best to use pointer casts, so that reference transmutation doesn't become an idiom applied even when inappropriate (cf. the push to replace the as operator with library functions).

1 Like