Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,20 @@ impl<Src: Clone, Dst: ?Sized + TryFromBytes> Clone for ValidityError<Src, Dst> {
}
}

// SAFETY: `ValidityError` contains a single `Self::Inner = Src`, and no other
// non-ZST fields. `map` passes ownership of `self`'s sole `Self::Inner` to `f`.
unsafe impl<Src, NewSrc, Dst> crate::pointer::TryWithError<NewSrc>
for crate::ValidityError<Src, Dst>
where
Dst: TryFromBytes + ?Sized,
{
type Inner = Src;
type Mapped = crate::ValidityError<NewSrc, Dst>;
fn map<F: FnOnce(Src) -> NewSrc>(self, f: F) -> Self::Mapped {
self.map_src(f)
}
}

impl<Src: PartialEq, Dst: ?Sized + TryFromBytes> PartialEq for ValidityError<Src, Dst> {
#[inline]
fn eq(&self, other: &Self) -> bool {
Expand Down Expand Up @@ -775,6 +789,22 @@ impl<Src, Dst: ?Sized> CastError<Src, Dst> {
}
}

// SAFETY: `CastError` is either a single `AlignmentError` or a single
// `SizeError`. In either case, it contains a single `Self::Inner = Src`, and no
// other non-ZST fields. `map` passes ownership of `self`'s sole `Self::Inner`
// to `f`.
unsafe impl<Src, NewSrc, Dst> crate::pointer::TryWithError<NewSrc> for crate::CastError<Src, Dst>
where
Dst: ?Sized,
{
type Inner = Src;
type Mapped = crate::CastError<NewSrc, Dst>;

fn map<F: FnOnce(Src) -> NewSrc>(self, f: F) -> Self::Mapped {
self.map_src(f)
}
}

impl<Src, Dst: ?Sized + Unaligned> From<CastError<Src, Dst>> for SizeError<Src, Dst> {
/// Infallibly extracts the [`SizeError`] from this `CastError` since `Dst`
/// is unaligned.
Expand Down
2 changes: 1 addition & 1 deletion src/pointer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub use {inner::PtrInner, transmute::*};
#[doc(hidden)]
pub use {
invariant::{BecauseExclusive, BecauseImmutable, Read},
ptr::Ptr,
ptr::*,
};

use crate::wrappers::ReadOnly;
Expand Down
84 changes: 84 additions & 0 deletions src/pointer/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,7 @@ mod _transitions {
}

/// Casts of the referent type.
pub(crate) use _casts::TryWithError;
mod _casts {
use core::cell::UnsafeCell;

Expand Down Expand Up @@ -912,6 +913,89 @@ mod _casts {
let tag = unsafe { tag.assume_alignment() };
tag.unify_invariants()
}

/// Attempts to transform the pointer, restoring the original on
/// failure.
///
/// # Safety
///
/// If `I::Aliasing != Shared`, then if `f` returns `Err(err)`, no copy
/// of `f`'s argument must exist outside of `err`.
#[inline(always)]
pub(crate) unsafe fn try_with_unchecked<U, J, E, F>(
self,
f: F,
) -> Result<Ptr<'a, U, J>, E::Mapped>
where
U: 'a + ?Sized,
J: Invariants<Aliasing = I::Aliasing>,
E: TryWithError<Self>,
F: FnOnce(Ptr<'a, T, I>) -> Result<Ptr<'a, U, J>, E>,
{
let old_inner = self.as_inner();
#[rustfmt::skip]
let res = f(self).map_err(#[inline(always)] move |err: E| {
err.map(#[inline(always)] |src| {
drop(src);

// SAFETY:
// 0. Aliasing is either `Shared` or `Exclusive`:
// - If aliasing is `Shared`, then it cannot violate
// aliasing make another copy of this pointer (in fact,
// using `I::Aliasing = Shared`, we could have just
// cloned `self`).
// - If aliasing is `Exclusive`, then `f` is not allowed
// to make another copy of `self`. In `map_err`, we are
// consuming the only value in the returned `Result`.
// By invariant on `E: TryWithError<Self>`, that `err:
// E` only contains a single `Self` and no other
// non-ZST fields which could be `Ptr`s or references
// to `self`'s referent. By the same invariant, `map`
// consumes this single `Self` and passes it to this
// closure. Since `self` was, by invariant on
// `Exclusive`, the only `Ptr` or reference live for
// `'a` with this referent, and since we `drop(src)`
// above, there are no copies left, and so we are
// creating the only copy.
// 1. `self` conforms to `I::Aliasing` by invariant on
// `Ptr`, and `old_inner` has the same address, so it
// does too.
// 2. `f` could not have violated `self`'s validity without
// itself being unsound. Assuming that `f` is sound, the
// referent of `self` is still valid for `T`.
unsafe { Ptr::from_inner(old_inner) }
})
});
res
}

/// Attempts to transform the pointer, restoring the original on
/// failure.
pub(crate) fn try_with<U, J, E, F>(self, f: F) -> Result<Ptr<'a, U, J>, E::Mapped>
where
U: 'a + ?Sized,
J: Invariants<Aliasing = I::Aliasing>,
E: TryWithError<Self>,
F: FnOnce(Ptr<'a, T, I>) -> Result<Ptr<'a, U, J>, E>,
I: Invariants<Aliasing = Shared>,
{
// SAFETY: `I::Aliasing = Shared`, so the safety condition does not
// apply.
unsafe { self.try_with_unchecked(f) }
}
}

/// # Safety
///
/// `Self` only contains a single `Self::Inner`, and `Self::Mapped` only
/// contains a single `MappedInner`. Other than that, `Self` and
/// `Self::Mapped` contain no non-ZST fields.
///
/// `map` must pass ownership of `self`'s sole `Self::Inner` to `f`.
pub(crate) unsafe trait TryWithError<MappedInner> {
type Inner;
type Mapped;
fn map<F: FnOnce(Self::Inner) -> MappedInner>(self, f: F) -> Self::Mapped;
}

impl<'a, T, I> Ptr<'a, T, I>
Expand Down
52 changes: 19 additions & 33 deletions src/util/macro_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ use crate::{
pointer::{
cast::CastSized,
invariant::{Aligned, Initialized, Valid},
BecauseInvariantsEq,
},
FromBytes, Immutable, IntoBytes, KnownLayout, Ptr, ReadOnly, TryFromBytes, ValidityError,
};
Expand Down Expand Up @@ -665,33 +664,21 @@ where
Dst: TryFromBytes + Immutable,
{
let ptr = Ptr::from_ref(src);
let ptr = ptr.recall_validity::<Initialized, _>();
let ptr = ptr.cast::<_, CastSized, _>();
match ptr.try_into_valid() {
#[rustfmt::skip]
let res = ptr.try_with(#[inline(always)] |ptr| {
let ptr = ptr.recall_validity::<Initialized, _>();
let ptr = ptr.cast::<_, CastSized, _>();
ptr.try_into_valid()
});
match res {
Ok(ptr) => {
static_assert!(Src, Dst => mem::align_of::<Dst>() <= mem::align_of::<Src>());
// SAFETY: We have checked that `Dst` does not have a stricter
// alignment requirement than `Src`.
let ptr = unsafe { ptr.assume_alignment::<Aligned>() };
Ok(ptr.as_ref())
}
Err(err) => Err(err.map_src(|ptr| {
let ptr = ptr.cast::<_, CastSized, _>();
// SAFETY: `ptr` has the same address as `src: &Src`, which is
// aligned by invariant on `&Src`.
let ptr = unsafe { ptr.assume_alignment::<Aligned>() };
// SAFETY: Because `Src: Immutable` and we create a `Ptr` via
// `Ptr::from_ref`, the resulting `Ptr` is a shared-and-`Immutable`
// `Ptr`, which does not permit mutation of its referent. Therefore,
// no mutation could have happened during the call to
// `try_into_valid` (any such mutation would be unsound).
//
// `try_into_valid` promises to return its original argument, and
// so we know that we are getting back the same `ptr` that we
// originally passed, and that `ptr` was a bit-valid `Src`.
let ptr = unsafe { ptr.assume_valid() };
ptr.as_ref()
})),
Err(err) => Err(err.map_src(Ptr::as_ref)),
}
}

Expand All @@ -714,25 +701,24 @@ where
Dst: TryFromBytes + IntoBytes,
{
let ptr = Ptr::from_mut(src);
let ptr = ptr.recall_validity::<Initialized, (_, (_, _))>();
let ptr = ptr.cast::<_, CastSized, _>();
match ptr.try_into_valid() {
// SAFETY: The provided closure returns the only copy of `ptr`.
#[rustfmt::skip]
let res = unsafe {
ptr.try_with_unchecked(#[inline(always)] |ptr| {
let ptr = ptr.recall_validity::<Initialized, (_, (_, _))>();
let ptr = ptr.cast::<_, CastSized, _>();
ptr.try_into_valid()
})
};
match res {
Ok(ptr) => {
static_assert!(Src, Dst => mem::align_of::<Dst>() <= mem::align_of::<Src>());
// SAFETY: We have checked that `Dst` does not have a stricter
// alignment requirement than `Src`.
let ptr = unsafe { ptr.assume_alignment::<Aligned>() };
Ok(ptr.as_mut())
}
Err(err) => {
Err(err.map_src(|ptr| {
let ptr = ptr.cast::<_, CastSized, _>();
// SAFETY: `ptr` has the same address as `src: &mut Src`, which
// is aligned by invariant on `&mut Src`.
let ptr = unsafe { ptr.assume_alignment::<Aligned>() };
ptr.recall_validity::<_, (_, BecauseInvariantsEq)>().as_mut()
}))
}
Err(err) => Err(err.map_src(Ptr::as_mut)),
}
}

Expand Down
6 changes: 3 additions & 3 deletions zerocopy-derive/tests/ui-nightly/enum.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ help: the trait `PaddingFree<IntoBytes1, 1>` is not implemented for `()`
but trait `PaddingFree<IntoBytes1, 0>` is implemented for it
--> $WORKSPACE/src/util/macro_util.rs
|
65 | impl<T: ?Sized> PaddingFree<T, 0> for () {}
64 | impl<T: ?Sized> PaddingFree<T, 0> for () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: see issue #48214
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
Expand All @@ -504,7 +504,7 @@ help: the trait `PaddingFree<IntoBytes2, 3>` is not implemented for `()`
but trait `PaddingFree<IntoBytes2, 0>` is implemented for it
--> $WORKSPACE/src/util/macro_util.rs
|
65 | impl<T: ?Sized> PaddingFree<T, 0> for () {}
64 | impl<T: ?Sized> PaddingFree<T, 0> for () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: see issue #48214
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
Expand All @@ -526,7 +526,7 @@ help: the trait `PaddingFree<IntoBytes3, 2>` is not implemented for `()`
but trait `PaddingFree<IntoBytes3, 0>` is implemented for it
--> $WORKSPACE/src/util/macro_util.rs
|
65 | impl<T: ?Sized> PaddingFree<T, 0> for () {}
64 | impl<T: ?Sized> PaddingFree<T, 0> for () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: see issue #48214
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
Expand Down
10 changes: 5 additions & 5 deletions zerocopy-derive/tests/ui-nightly/struct.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ help: the trait `PaddingFree<IntoBytes2, 1>` is not implemented for `()`
but trait `PaddingFree<IntoBytes2, 0>` is implemented for it
--> $WORKSPACE/src/util/macro_util.rs
|
65 | impl<T: ?Sized> PaddingFree<T, 0> for () {}
64 | impl<T: ?Sized> PaddingFree<T, 0> for () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: see issue #48214
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
Expand All @@ -347,7 +347,7 @@ help: the trait `PaddingFree<IntoBytes3, 1>` is not implemented for `()`
but trait `PaddingFree<IntoBytes3, 0>` is implemented for it
--> $WORKSPACE/src/util/macro_util.rs
|
65 | impl<T: ?Sized> PaddingFree<T, 0> for () {}
64 | impl<T: ?Sized> PaddingFree<T, 0> for () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: see issue #48214
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
Expand Down Expand Up @@ -405,7 +405,7 @@ help: the trait `DynamicPaddingFree<IntoBytes5, true>` is not implemented for `(
but trait `DynamicPaddingFree<IntoBytes5, false>` is implemented for it
--> $WORKSPACE/src/util/macro_util.rs
|
83 | impl<T: ?Sized> DynamicPaddingFree<T, false> for () {}
82 | impl<T: ?Sized> DynamicPaddingFree<T, false> for () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: see issue #48214
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
Expand All @@ -427,7 +427,7 @@ help: the trait `DynamicPaddingFree<IntoBytes6, true>` is not implemented for `(
but trait `DynamicPaddingFree<IntoBytes6, false>` is implemented for it
--> $WORKSPACE/src/util/macro_util.rs
|
83 | impl<T: ?Sized> DynamicPaddingFree<T, false> for () {}
82 | impl<T: ?Sized> DynamicPaddingFree<T, false> for () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: see issue #48214
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
Expand All @@ -449,7 +449,7 @@ help: the trait `DynamicPaddingFree<IntoBytes7, true>` is not implemented for `(
but trait `DynamicPaddingFree<IntoBytes7, false>` is implemented for it
--> $WORKSPACE/src/util/macro_util.rs
|
83 | impl<T: ?Sized> DynamicPaddingFree<T, false> for () {}
82 | impl<T: ?Sized> DynamicPaddingFree<T, false> for () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: see issue #48214
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
Expand Down
6 changes: 3 additions & 3 deletions zerocopy-derive/tests/ui-stable/enum.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ help: the trait `PaddingFree<IntoBytes1, 1>` is not implemented for `()`
but trait `PaddingFree<IntoBytes1, 0>` is implemented for it
--> $WORKSPACE/src/util/macro_util.rs
|
65 | impl<T: ?Sized> PaddingFree<T, 0> for () {}
64 | impl<T: ?Sized> PaddingFree<T, 0> for () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: see issue #48214
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
Expand All @@ -457,7 +457,7 @@ help: the trait `PaddingFree<IntoBytes2, 3>` is not implemented for `()`
but trait `PaddingFree<IntoBytes2, 0>` is implemented for it
--> $WORKSPACE/src/util/macro_util.rs
|
65 | impl<T: ?Sized> PaddingFree<T, 0> for () {}
64 | impl<T: ?Sized> PaddingFree<T, 0> for () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: see issue #48214
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
Expand All @@ -475,7 +475,7 @@ help: the trait `PaddingFree<IntoBytes3, 2>` is not implemented for `()`
but trait `PaddingFree<IntoBytes3, 0>` is implemented for it
--> $WORKSPACE/src/util/macro_util.rs
|
65 | impl<T: ?Sized> PaddingFree<T, 0> for () {}
64 | impl<T: ?Sized> PaddingFree<T, 0> for () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: see issue #48214
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
Expand Down
10 changes: 5 additions & 5 deletions zerocopy-derive/tests/ui-stable/struct.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ help: the trait `PaddingFree<IntoBytes2, 1>` is not implemented for `()`
but trait `PaddingFree<IntoBytes2, 0>` is implemented for it
--> $WORKSPACE/src/util/macro_util.rs
|
65 | impl<T: ?Sized> PaddingFree<T, 0> for () {}
64 | impl<T: ?Sized> PaddingFree<T, 0> for () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: see issue #48214
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
Expand All @@ -311,7 +311,7 @@ help: the trait `PaddingFree<IntoBytes3, 1>` is not implemented for `()`
but trait `PaddingFree<IntoBytes3, 0>` is implemented for it
--> $WORKSPACE/src/util/macro_util.rs
|
65 | impl<T: ?Sized> PaddingFree<T, 0> for () {}
64 | impl<T: ?Sized> PaddingFree<T, 0> for () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: see issue #48214
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
Expand Down Expand Up @@ -365,7 +365,7 @@ help: the trait `DynamicPaddingFree<IntoBytes5, true>` is not implemented for `(
but trait `DynamicPaddingFree<IntoBytes5, false>` is implemented for it
--> $WORKSPACE/src/util/macro_util.rs
|
83 | impl<T: ?Sized> DynamicPaddingFree<T, false> for () {}
82 | impl<T: ?Sized> DynamicPaddingFree<T, false> for () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: see issue #48214
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
Expand All @@ -383,7 +383,7 @@ help: the trait `DynamicPaddingFree<IntoBytes6, true>` is not implemented for `(
but trait `DynamicPaddingFree<IntoBytes6, false>` is implemented for it
--> $WORKSPACE/src/util/macro_util.rs
|
83 | impl<T: ?Sized> DynamicPaddingFree<T, false> for () {}
82 | impl<T: ?Sized> DynamicPaddingFree<T, false> for () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: see issue #48214
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
Expand All @@ -401,7 +401,7 @@ help: the trait `DynamicPaddingFree<IntoBytes7, true>` is not implemented for `(
but trait `DynamicPaddingFree<IntoBytes7, false>` is implemented for it
--> $WORKSPACE/src/util/macro_util.rs
|
83 | impl<T: ?Sized> DynamicPaddingFree<T, false> for () {}
82 | impl<T: ?Sized> DynamicPaddingFree<T, false> for () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: see issue #48214
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
Expand Down
Loading