zerocopy icon indicating copy to clipboard operation
zerocopy copied to clipboard

Implement `Ref::{try_as_ref,try_into_ref,try_into_mut}`

Open jswrenn opened this issue 1 year ago • 1 comments
trafficstars

Only Ref::try_as_mut remains missing, probably pending polonius landing in rustc.

Partially fixes #1865 Supersedes #1184

A restricted form of Ref::try_as_mut can be implemented now as:

impl<B, T> Ref<B, T>
where
    B: ByteSlice,
    T: KnownLayout + ?Sized,
{
    #[must_use = "has no side effects"]
    #[inline(always)]
    pub fn try_as_mut(r: &mut Self) -> Result<&mut T, ValidityError<&mut Self, T>>
    where
        T: TryFromBytes + Immutable,
        B: ByteSliceMut + CloneableByteSlice,
    {
        // Presumably unreachable, since we've guarded each constructor of `Ref`.
        static_assert_dst_is_not_zst!(T);

        // Due to a false-positive in Rust's current borrow checker, the same
        // `r` can't be used for both validation *and* be returned upon
        // validation failure. We use `r_tmp` for validation, and `r` as the
        // value returned upon failure.
        let mut r_tmp = r.clone();

        // SAFETY: We don't call any methods on `t` other than those provided by
        // `ByteSlice`.
        let b = unsafe { r_tmp.as_byte_slice_mut() };

        match Ptr::from_mut(b.deref_mut()).try_cast_into_no_leftover::<T, BecauseExclusive>(None) {
            Ok(candidate) => match candidate.try_into_valid() {
                Ok(valid) => {
                    // SAFETY: `valid` inherits the local lifetime of `r_tmp`,
                    // but its value is derived from `r_tmp`'s underlying bytes.
                    // By contract on `CloneableByteSlice`, `r_temp.deref()
                    // produces a byte slice whose address (and thus lifetime)
                    // is identicial to that produced by `r.deref()`. We can
                    // therefor soundly extend the lifetime of `valid` to that
                    // of `r`.
                    Ok(unsafe { valid.assume_lifetime() }.as_mut())
                },
                Err(e) => Err(e.with_src(r)),
            },
            Err(CastError::Validity(i)) => match i {},
            Err(CastError::Alignment(_) | CastError::Size(_)) => {
                // SAFETY: By invariant on `Ref::0`, the referenced byte slice
                // is aligned to `T`'s alignment and its size corresponds to a
                // valid size for `T`. Since properties are checked upon
                // constructing `Ref`, these failures are unreachable.
                unsafe { core::hint::unreachable_unchecked() }
            }
        }
    }
}

...but we don't yet implement ClonableByteSlice for anything except &[u8], so the method is effectively untestable.

jswrenn avatar Oct 17 '24 19:10 jswrenn

Codecov Report

:x: Patch coverage is 94.87179% with 6 lines in your changes missing coverage. Please review. :white_check_mark: Project coverage is 87.72%. Comparing base (0bee231) to head (311a259). :warning: Report is 76 commits behind head on v0.8.x.

Files with missing lines Patch % Lines
src/ref.rs 94.59% 6 Missing :warning:
Additional details and impacted files
@@            Coverage Diff             @@
##           v0.8.x    #1930      +/-   ##
==========================================
+ Coverage   87.59%   87.72%   +0.13%     
==========================================
  Files          16       16              
  Lines        5988     6103     +115     
==========================================
+ Hits         5245     5354     +109     
- Misses        743      749       +6     

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

:rocket: New features to boost your workflow:
  • :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

codecov-commenter avatar Oct 18 '24 17:10 codecov-commenter