Convert &[u8; N] to a shared reference to a newtype around [u8; N]

pub struct Foo<const N: usize>([u8; N]);
impl<'a: 'b, 'b, const N: usize> From<&'a [u8; N]> for &'b Foo<N>
{
    fn from(value: &'a [u8; N]) -> Self {
        let ptr = value.as_ptr() as *const Foo<N>;
        // SAFETY:
        // https://doc.rust-lang.org/core/ptr/index.html#pointer-to-reference-conversion:
        // * The pointer must be properly aligned: I think.
        // * It must be non-null: yes since references are always non-null.
        // * It must be “dereferenceable” in the sense defined above: I think.
        // * The pointer must point to a valid value of type `T`: yes since references always point to a valid value.
        // * You must enforce Rust’s aliasing rules. The exact aliasing rules are not decided yet, so we only give a rough overview here. The rules also depend on whether a mutable or a shared reference is being created.
        //     * When creating a mutable reference, then while this reference exists, the memory it points to must not get accessed (read or written) through any other pointer or reference not derived from this reference: vacuously satisfied (i.e., a shared reference is constructed).
        //     * When creating a shared reference, then while this reference exists, the memory it points to must not get mutated (except inside `UnsafeCell`): yes unless calling code uses `unsafe` code to mutate the value which I believe is always UB.
        unsafe { &*ptr }
    }
}

Is the above code safe? Is the SAFETY comment correct? Is it fine to possibly shorten the lifetime, or must I return the same lifetime parameter?

I'm terrified of most unsafe code since I know so little about pointers and concepts like pointer provenance. If I can safely do this conversion, then I'd rather do that; but I don't think I can. N may be quite large, and I don't want to force people to Copy the value.

Almost, but no. You need #[repr(transparent)] on Foo, as otherwise the layout of Foo is unspecified and is allowed to differ from [u8; N].

2 Likes

See also:

  • or, if you're already using bytemuck - Rust, check out its TransparentWrapper derive and utilities
3 Likes

Ah, I should have known that. Is the possible lifetime shortening fine?

Yes, that part is fine.

1 Like