Skip to content
Open
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
23 changes: 17 additions & 6 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,9 @@ use core::{
#[cfg(all(no_zerocopy_core_error_1_81_0, any(feature = "std", test)))]
use std::error::Error;

use crate::{util::SendSyncPhantomData, KnownLayout, TryFromBytes, Unaligned};
use crate::{
pointer::TryWithError, util::SendSyncPhantomData, KnownLayout, TryFromBytes, Unaligned,
};
#[cfg(doc)]
use crate::{FromBytes, Ref};

Expand Down Expand Up @@ -355,6 +357,16 @@ impl<Src: PartialEq, Dst: ?Sized> PartialEq for AlignmentError<Src, Dst> {

impl<Src: Eq, Dst: ?Sized> Eq for AlignmentError<Src, Dst> {}

// SAFETY: `AlignmentError` 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: ?Sized> TryWithError<NewSrc> for AlignmentError<Src, Dst> {
type Inner = Src;
type Mapped = AlignmentError<NewSrc, Dst>;
fn map<F: FnOnce(Src) -> NewSrc>(self, f: F) -> Self::Mapped {
self.map_src(f)
}
}

impl<Src, Dst: ?Sized + Unaligned> From<AlignmentError<Src, Dst>> for Infallible {
#[inline(always)]
fn from(_: AlignmentError<Src, Dst>) -> Infallible {
Expand Down Expand Up @@ -655,13 +667,12 @@ 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>
unsafe impl<Src, NewSrc, Dst> TryWithError<NewSrc> for ValidityError<Src, Dst>
where
Dst: TryFromBytes + ?Sized,
{
type Inner = Src;
type Mapped = crate::ValidityError<NewSrc, Dst>;
type Mapped = ValidityError<NewSrc, Dst>;
fn map<F: FnOnce(Src) -> NewSrc>(self, f: F) -> Self::Mapped {
self.map_src(f)
}
Expand Down Expand Up @@ -793,12 +804,12 @@ impl<Src, Dst: ?Sized> CastError<Src, Dst> {
// `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>
unsafe impl<Src, NewSrc, Dst> TryWithError<NewSrc> for CastError<Src, Dst>
where
Dst: ?Sized,
{
type Inner = Src;
type Mapped = crate::CastError<NewSrc, Dst>;
type Mapped = CastError<NewSrc, Dst>;

fn map<F: FnOnce(Src) -> NewSrc>(self, f: F) -> Self::Mapped {
self.map_src(f)
Expand Down
44 changes: 24 additions & 20 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3775,10 +3775,12 @@ pub unsafe trait FromBytes: FromZeros {
Self: KnownLayout + Immutable,
{
static_assert_dst_is_not_zst!(Self);
match Ptr::from_ref(source).try_cast_into_no_leftover::<_, BecauseImmutable>(None) {
Ok(ptr) => Ok(ptr.recall_validity().as_ref()),
Err(err) => Err(err.map_src(|src| src.as_ref())),
}
#[rustfmt::skip]
return Ptr::from_ref(source).try_with_as_ref(#[inline(always)] |ptr| {
ptr.try_cast_into_no_leftover::<_, BecauseImmutable>(None)
.map(Ptr::recall_validity)
.map_err(|err| err.map_src(drop))
});
}

/// Interprets the prefix of the given `source` as a `&Self` without
Expand Down Expand Up @@ -4011,10 +4013,12 @@ pub unsafe trait FromBytes: FromZeros {
Self: IntoBytes + KnownLayout,
{
static_assert_dst_is_not_zst!(Self);
match Ptr::from_mut(source).try_cast_into_no_leftover::<_, BecauseExclusive>(None) {
Ok(ptr) => Ok(ptr.recall_validity::<_, (_, (_, _))>().as_mut()),
Err(err) => Err(err.map_src(|src| src.as_mut())),
}
#[rustfmt::skip]
return Ptr::from_mut(source).try_with_as_mut(#[inline(always)] |ptr| {
ptr.try_cast_into_no_leftover::<_, BecauseExclusive>(None)
.map(Ptr::recall_validity::<_, (_, (_, _))>)
.map_err(|err| err.map_src(drop))
});
}

/// Interprets the prefix of the given `source` as a `&mut Self` without
Expand Down Expand Up @@ -4248,12 +4252,12 @@ pub unsafe trait FromBytes: FromZeros {
where
Self: KnownLayout<PointerMetadata = usize> + Immutable,
{
let source = Ptr::from_ref(source);
let maybe_slf = source.try_cast_into_no_leftover::<_, BecauseImmutable>(Some(count));
match maybe_slf {
Ok(slf) => Ok(slf.recall_validity().as_ref()),
Err(err) => Err(err.map_src(|s| s.as_ref())),
}
#[rustfmt::skip]
return Ptr::from_ref(source).try_with_as_ref(#[inline(always)] |ptr| {
ptr.try_cast_into_no_leftover::<_, BecauseImmutable>(Some(count))
.map(Ptr::recall_validity)
.map_err(|err| err.map_src(drop))
});
}

/// Interprets the prefix of the given `source` as a DST `&Self` with length
Expand Down Expand Up @@ -4479,12 +4483,12 @@ pub unsafe trait FromBytes: FromZeros {
where
Self: IntoBytes + KnownLayout<PointerMetadata = usize> + Immutable,
{
let source = Ptr::from_mut(source);
let maybe_slf = source.try_cast_into_no_leftover::<_, BecauseImmutable>(Some(count));
match maybe_slf {
Ok(slf) => Ok(slf.recall_validity::<_, (_, (_, BecauseExclusive))>().as_mut()),
Err(err) => Err(err.map_src(|s| s.as_mut())),
}
#[rustfmt::skip]
return Ptr::from_mut(source).try_with_as_mut(#[inline(always)] |ptr| {
ptr.try_cast_into_no_leftover::<_, BecauseImmutable>(Some(count))
.map(Ptr::recall_validity::<_, (_, (_, BecauseExclusive))>)
.map_err(|err| err.map_src(drop))
});
}

/// Interprets the prefix of the given `source` as a `&mut Self` with DST
Expand Down
63 changes: 60 additions & 3 deletions src/pointer/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,10 @@ mod _external {
/// Methods for converting to and from `Ptr` and Rust's safe reference types.
mod _conversions {
use super::*;
use crate::pointer::cast::{CastExact, CastSized, IdCast};
use crate::{
pointer::cast::{CastExact, CastSized, IdCast},
Unalign,
};

/// `&'a T` → `Ptr<'a, T>`
impl<'a, T> Ptr<'a, T, (Shared, Aligned, Valid)>
Expand Down Expand Up @@ -371,9 +374,10 @@ mod _conversions {
}

/// `Ptr<'a, T>` → `&'a mut T`
impl<'a, T> Ptr<'a, T, (Exclusive, Aligned, Valid)>
impl<'a, T, I> Ptr<'a, T, I>
where
T: 'a + ?Sized,
I: Invariants<Aliasing = Exclusive, Alignment = Aligned, Validity = Valid>,
{
/// Converts `self` to a mutable reference.
#[allow(clippy::wrong_self_convention)]
Expand Down Expand Up @@ -548,7 +552,7 @@ mod _conversions {
/// `Unalign<T>`.
pub(crate) fn into_unalign(
self,
) -> Ptr<'a, crate::Unalign<T>, (I::Aliasing, Aligned, I::Validity)> {
) -> Ptr<'a, Unalign<T>, (I::Aliasing, Aligned, I::Validity)> {
// FIXME(#1359): This should be a `transmute_with` call.
// Unfortunately, to avoid blanket impl conflicts, we only implement
// `TransmuteFrom<T>` for `Unalign<T>` (and vice versa) specifically
Expand Down Expand Up @@ -971,6 +975,59 @@ mod _casts {
}
}

// TODO: Unify these two methods and delegate to `Ptr::as_ref` or
// `Ptr::as_mut` automatically.

impl<'a, T, I> Ptr<'a, T, I>
where
T: 'a + ?Sized,
I: Invariants<Aliasing = Shared, Alignment = Aligned, Validity = Valid>,
{
/// Like [`try_with`], but returns a reference instead of a pointer
/// in both the success and error cases.
pub(crate) fn try_with_as_ref<U, J, E, F>(
self,
f: F,
) -> Result<&'a U, <E::Mapped as TryWithError<&'a T>>::Mapped>
where
U: 'a + ?Sized,
J: Invariants<Aliasing = Shared, Alignment = Aligned, Validity = Valid>,
E: TryWithError<Self>,
E::Mapped: TryWithError<&'a T, Inner = Self>,
F: for<'b> FnOnce(Ptr<'b, T, I>) -> Result<Ptr<'b, U, J>, E>,
{
match self.try_with(f) {
Ok(ptr) => Ok(ptr.as_ref()),
Err(err) => Err(TryWithError::map(err, Ptr::as_ref)),
}
}
}

impl<'a, T, I> Ptr<'a, T, I>
where
T: 'a + ?Sized,
I: Invariants<Aliasing = Exclusive, Alignment = Aligned, Validity = Valid>,
{
/// Like [`try_with`], but returns a mutable reference instead of a
/// pointer in both the success and error cases.
pub(crate) fn try_with_as_mut<U, J, E, F>(
self,
f: F,
) -> Result<&'a mut U, <E::Mapped as TryWithError<&'a mut T>>::Mapped>
where
U: 'a + ?Sized,
J: Invariants<Aliasing = Exclusive, Alignment = Aligned, Validity = Valid>,
E: TryWithError<Self>,
E::Mapped: TryWithError<&'a mut T, Inner = Self>,
F: for<'b> FnOnce(Ptr<'b, T, I>) -> Result<Ptr<'b, U, J>, E>,
{
match self.try_with(f) {
Ok(ptr) => Ok(ptr.as_mut()),
Err(err) => Err(TryWithError::map(err, Ptr::as_mut)),
}
}
}

/// # Safety
///
/// `Self` only contains a single `Self::Inner`, and `Self::Mapped` only
Expand Down
2 changes: 1 addition & 1 deletion src/split_at.rs
Original file line number Diff line number Diff line change
Expand Up @@ -700,7 +700,7 @@ where
// SAFETY: `self.source.as_mut()` points to exactly the same referent as
// `self.source` and thus maintains the invariants of `self` with
// respect to `l_len`.
unsafe { Split::new(self.source.unify_invariants().as_mut(), self.l_len) }
unsafe { Split::new(self.source.as_mut(), self.l_len) }
}

/// Produces the length of `self`'s left part.
Expand Down
30 changes: 10 additions & 20 deletions src/util/macro_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -665,21 +665,16 @@ where
{
let ptr = Ptr::from_ref(src);
#[rustfmt::skip]
let res = ptr.try_with(#[inline(always)] |ptr| {
return ptr.try_with_as_ref(#[inline(always)] |ptr| {
let ptr = ptr.recall_validity::<Initialized, _>();
let ptr = ptr.cast::<_, CastSized, _>();
ptr.try_into_valid().map_err(|err| err.map_src(drop))
});
match res {
Ok(ptr) => {
ptr.try_into_valid().map(#[inline(always)] |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::as_ref)),
}
unsafe { ptr.assume_alignment::<Aligned>() }
}).map_err(|err| err.map_src(drop))
});
}

/// Attempts to transmute `&mut Src` into `&mut Dst`.
Expand All @@ -702,21 +697,16 @@ where
{
let ptr = Ptr::from_mut(src);
#[rustfmt::skip]
let res = ptr.try_with(#[inline(always)] |ptr| {
return ptr.try_with_as_mut(#[inline(always)] |ptr| {
let ptr = ptr.recall_validity::<Initialized, (_, (_, _))>();
let ptr = ptr.cast::<_, CastSized, _>();
ptr.try_into_valid().map_err(|err| err.map_src(drop))
});
match res {
Ok(ptr) => {
ptr.try_into_valid().map(#[inline(always)] |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::as_mut)),
}
unsafe { ptr.assume_alignment::<Aligned>() }
}).map_err(|err| err.map_src(drop))
});
}

// Used in `transmute_ref!` and friends.
Expand Down
10 changes: 5 additions & 5 deletions src/wrappers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,11 +198,11 @@ impl<T> Unalign<T> {
/// may prefer [`Deref::deref`], which is infallible.
#[inline(always)]
pub fn try_deref(&self) -> Result<&T, AlignmentError<&Self, T>> {
let inner = Ptr::from_ref(self).transmute();
match inner.try_into_aligned() {
Ok(aligned) => Ok(aligned.as_ref()),
Err(err) => Err(err.map_src(|src| src.into_unalign().as_ref())),
}
let ptr = Ptr::from_ref(self);
#[rustfmt::skip]
return ptr.try_with_as_ref(#[inline(always)] |ptr| {
ptr.transmute().try_into_aligned().map_err(|err| err.map_src(drop))
});
}

/// Attempts to return a mutable reference to the wrapped `T`, failing if
Expand Down
Loading