Skip to content

Implement try_transmute! #1013

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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions