Skip to content

Implement try_transmute! #1013

@jswrenn

Description

@jswrenn

We should implement try_transmute!, analogous to transmute!, that performs compile-time size and alignment checks, but also a run-time validity check.

Considerations

Due to the run-time validity check, this macro will not be usable in const contexts for the foreseeable future. (But we could perhaps work around this by also providing const fn is_bit_valid inherent methods in our derive; see #115.)

The implementation should avoid performing dynamic size or alignment checks.

Steps

Once #999 is merged, we can define a typed alternative to is_bit_valid on TryFromBytes:

#[doc(hidden)]
#[inline]
fn is_src_valid<Src>(src: &mut Src) -> bool
where
    Src: IntoBytes,
    Self: Sized,
{
    let c_ptr = crate::Ptr::from_mut(src);

    if mem::size_of::<Src>() > mem::size_of::<Self>() {
        return false;
    }

    // SAFETY:
    // - `size_of::<Src>()` <= `size_of::<Self>()`
    // - `c_ptr` is exclusively aliased, so we do not need to reason about
    //   `UnsafeCell`
    let c_ptr = unsafe { c_ptr.cast_unsized(|p| p as *mut Self) };

    // SAFETY: `c_ptr` is derived from `src` which is `IntoBytes`. By
    // invariant on `IntoByte`s, `c_ptr`'s referent consists entirely of
    // initialized bytes.
    let c_ptr = unsafe { c_ptr.assume_validity::<crate::invariant::Initialized>() };

    Self::is_bit_valid(c_ptr)
}

The dynamic components of try_transmute! can then be factored into a helper function:

/// A helper for `try_transmute!`.
#[inline(always)]
pub fn try_transmute<Src, Dst>(mut src: Src) -> Option<Dst>
where
    Src: IntoBytes,
    Dst: TryFromBytes,
{
    if !Dst::is_src_valid(&mut src) {
        return None;
    }

    let src = ManuallyDrop::new(src);

    // SAFETY:
    // - `src` is a bit-valid instance of `Dst`
    // - `src` is `ManuallyDrop`
    Some(unsafe { core::mem::transmute_copy(&*src) })
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions