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
125 changes: 106 additions & 19 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ use crate::{FromBytes, Ref};
/// - [`CastError`]: the error type of reference conversions
/// - [`TryCastError`]: the error type of fallible reference conversions
/// - [`TryReadError`]: the error type of fallible read conversions
#[derive(PartialEq, Eq)]
#[derive(PartialEq, Eq, Clone)]
pub enum ConvertError<A, S, V> {
/// The conversion source was improperly aligned.
Alignment(A),
Expand Down Expand Up @@ -242,15 +242,14 @@ where
}

/// The error emitted if the conversion source is improperly aligned.
#[derive(PartialEq, Eq)]
pub struct AlignmentError<Src, Dst: ?Sized> {
/// The source value involved in the conversion.
src: Src,
/// The inner destination type inolved in the conversion.
/// The inner destination type involved in the conversion.
///
/// INVARIANT: An `AlignmentError` may only be constructed if `Dst`'s
/// alignment requirement is greater than one.
dst: SendSyncPhantomData<Dst>,
_dst: SendSyncPhantomData<Dst>,
}

impl<Src, Dst: ?Sized> AlignmentError<Src, Dst> {
Expand All @@ -261,7 +260,7 @@ impl<Src, Dst: ?Sized> AlignmentError<Src, Dst> {
pub(crate) unsafe fn new_unchecked(src: Src) -> Self {
// INVARIANT: The caller guarantees that `Dst`'s alignment requirement
// is greater than one.
Self { src, dst: SendSyncPhantomData::default() }
Self { src, _dst: SendSyncPhantomData::default() }
}

/// Produces the source underlying the failed conversion.
Expand All @@ -274,7 +273,7 @@ impl<Src, Dst: ?Sized> AlignmentError<Src, Dst> {
// INVARIANT: `with_src` doesn't change the type of `Dst`, so the
// invariant that `Dst`'s alignment requirement is greater than one is
// preserved.
AlignmentError { src: new_src, dst: SendSyncPhantomData::default() }
AlignmentError { src: new_src, _dst: SendSyncPhantomData::default() }
}

/// Maps the source value associated with the conversion error.
Expand All @@ -299,7 +298,7 @@ impl<Src, Dst: ?Sized> AlignmentError<Src, Dst> {
/// ```
#[inline]
pub fn map_src<NewSrc>(self, f: impl FnOnce(Src) -> NewSrc) -> AlignmentError<NewSrc, Dst> {
AlignmentError { src: f(self.src), dst: SendSyncPhantomData::default() }
AlignmentError { src: f(self.src), _dst: SendSyncPhantomData::default() }
}

pub(crate) fn into<S, V>(self) -> ConvertError<Self, S, V> {
Expand Down Expand Up @@ -337,6 +336,22 @@ impl<Src, Dst: ?Sized> AlignmentError<Src, Dst> {
}
}

impl<Src: Clone, Dst: ?Sized> Clone for AlignmentError<Src, Dst> {
#[inline]
fn clone(&self) -> Self {
Self { src: self.src.clone(), _dst: SendSyncPhantomData::default() }
}
}

impl<Src: PartialEq, Dst: ?Sized> PartialEq for AlignmentError<Src, Dst> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.src == other.src
}
}

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

impl<Src, Dst: ?Sized + Unaligned> From<AlignmentError<Src, Dst>> for Infallible {
#[inline(always)]
fn from(_: AlignmentError<Src, Dst>) -> Infallible {
Expand Down Expand Up @@ -408,17 +423,16 @@ impl<Src, Dst: ?Sized, S, V> From<AlignmentError<Src, Dst>>
}

/// The error emitted if the conversion source is of incorrect size.
#[derive(PartialEq, Eq)]
pub struct SizeError<Src, Dst: ?Sized> {
/// The source value involved in the conversion.
src: Src,
/// The inner destination type inolved in the conversion.
dst: SendSyncPhantomData<Dst>,
/// The inner destination type involved in the conversion.
_dst: SendSyncPhantomData<Dst>,
}

impl<Src, Dst: ?Sized> SizeError<Src, Dst> {
pub(crate) fn new(src: Src) -> Self {
Self { src, dst: SendSyncPhantomData::default() }
Self { src, _dst: SendSyncPhantomData::default() }
}

/// Produces the source underlying the failed conversion.
Expand All @@ -429,7 +443,7 @@ impl<Src, Dst: ?Sized> SizeError<Src, Dst> {

/// Sets the source value associated with the conversion error.
pub(crate) fn with_src<NewSrc>(self, new_src: NewSrc) -> SizeError<NewSrc, Dst> {
SizeError { src: new_src, dst: SendSyncPhantomData::default() }
SizeError { src: new_src, _dst: SendSyncPhantomData::default() }
}

/// Maps the source value associated with the conversion error.
Expand All @@ -455,12 +469,12 @@ impl<Src, Dst: ?Sized> SizeError<Src, Dst> {
/// ```
#[inline]
pub fn map_src<NewSrc>(self, f: impl FnOnce(Src) -> NewSrc) -> SizeError<NewSrc, Dst> {
SizeError { src: f(self.src), dst: SendSyncPhantomData::default() }
SizeError { src: f(self.src), _dst: SendSyncPhantomData::default() }
}

/// Sets the destination type associated with the conversion error.
pub(crate) fn with_dst<NewDst: ?Sized>(self) -> SizeError<Src, NewDst> {
SizeError { src: self.src, dst: SendSyncPhantomData::default() }
SizeError { src: self.src, _dst: SendSyncPhantomData::default() }
}

/// Converts the error into a general [`ConvertError`].
Expand Down Expand Up @@ -507,6 +521,22 @@ impl<Src, Dst: ?Sized> SizeError<Src, Dst> {
}
}

impl<Src: Clone, Dst: ?Sized> Clone for SizeError<Src, Dst> {
#[inline]
fn clone(&self) -> Self {
Self { src: self.src.clone(), _dst: SendSyncPhantomData::default() }
}
}

impl<Src: PartialEq, Dst: ?Sized> PartialEq for SizeError<Src, Dst> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.src == other.src
}
}

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

impl<Src, Dst: ?Sized> fmt::Debug for SizeError<Src, Dst> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand Down Expand Up @@ -552,17 +582,16 @@ impl<Src, Dst: ?Sized, A, V> From<SizeError<Src, Dst>> for ConvertError<A, SizeE
}

/// The error emitted if the conversion source contains invalid data.
#[derive(PartialEq, Eq)]
pub struct ValidityError<Src, Dst: ?Sized + TryFromBytes> {
/// The source value involved in the conversion.
pub(crate) src: Src,
/// The inner destination type inolved in the conversion.
dst: SendSyncPhantomData<Dst>,
/// The inner destination type involved in the conversion.
_dst: SendSyncPhantomData<Dst>,
}

impl<Src, Dst: ?Sized + TryFromBytes> ValidityError<Src, Dst> {
pub(crate) fn new(src: Src) -> Self {
Self { src, dst: SendSyncPhantomData::default() }
Self { src, _dst: SendSyncPhantomData::default() }
}

/// Produces the source underlying the failed conversion.
Expand Down Expand Up @@ -593,7 +622,7 @@ impl<Src, Dst: ?Sized + TryFromBytes> ValidityError<Src, Dst> {
/// ```
#[inline]
pub fn map_src<NewSrc>(self, f: impl FnOnce(Src) -> NewSrc) -> ValidityError<NewSrc, Dst> {
ValidityError { src: f(self.src), dst: SendSyncPhantomData::default() }
ValidityError { src: f(self.src), _dst: SendSyncPhantomData::default() }
}

/// Converts the error into a general [`ConvertError`].
Expand All @@ -614,6 +643,22 @@ impl<Src, Dst: ?Sized + TryFromBytes> ValidityError<Src, Dst> {
}
}

impl<Src: Clone, Dst: ?Sized + TryFromBytes> Clone for ValidityError<Src, Dst> {
#[inline]
fn clone(&self) -> Self {
Self { src: self.src.clone(), _dst: SendSyncPhantomData::default() }
}
}

impl<Src: PartialEq, Dst: ?Sized + TryFromBytes> PartialEq for ValidityError<Src, Dst> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.src == other.src
}
}

impl<Src: Eq, Dst: ?Sized + TryFromBytes> Eq for ValidityError<Src, Dst> {}

impl<Src, Dst: ?Sized + TryFromBytes> fmt::Debug for ValidityError<Src, Dst> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand Down Expand Up @@ -993,6 +1038,48 @@ mod tests {
}
}

#[test]
fn test_eq_partial_eq_clone() {
// Test that all error types implement `Eq`, `PartialEq`
// and `Clone` if src does
// even if `Dst: !Eq`, `!PartialEq`, `!Clone`.

#[allow(dead_code)]
fn is_eq_partial_eq_clone<T: Eq + PartialEq + Clone>(_t: T) {}

#[allow(dead_code)]
fn alignment_err_is_eq_partial_eq_clone<Src: Eq + PartialEq + Clone, Dst>(
err: AlignmentError<Src, Dst>,
) {
is_eq_partial_eq_clone(err)
}

#[allow(dead_code)]
fn size_err_is_eq_partial_eq_clone<Src: Eq + PartialEq + Clone, Dst>(
err: SizeError<Src, Dst>,
) {
is_eq_partial_eq_clone(err)
}

#[allow(dead_code)]
fn validity_err_is_eq_partial_eq_clone<Src: Eq + PartialEq + Clone, Dst: TryFromBytes>(
err: ValidityError<Src, Dst>,
) {
is_eq_partial_eq_clone(err)
}

#[allow(dead_code)]
fn convert_error_is_eq_partial_eq_clone<Src: Eq + PartialEq + Clone, Dst: TryFromBytes>(
err: ConvertError<
AlignmentError<Src, Dst>,
SizeError<Src, Dst>,
ValidityError<Src, Dst>,
>,
) {
is_eq_partial_eq_clone(err)
}
}

#[test]
fn alignment_display() {
#[repr(C, align(128))]
Expand Down
2 changes: 1 addition & 1 deletion src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -812,7 +812,7 @@ unsafe impl<T: TryFromBytes + ?Sized> TryFromBytes for UnsafeCell<T> {
//
// `is_bit_valid` is documented as panicking or failing to monomorphize
// if called with a shared-aliased pointer on a type containing an
// `UnsafeCell`. In practice, it will always be a monorphization error.
// `UnsafeCell`. In practice, it will always be a monomorphization error.
// Since `is_bit_valid` is `#[doc(hidden)]` and only called directly
// from this crate, we only need to worry about our own code incorrectly
// calling `UnsafeCell::is_bit_valid`. The post-monomorphization error
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,7 @@ use {FromZeros as FromZeroes, IntoBytes as AsBytes, Ref as LayoutVerified};
/// example.
///
/// A `#[repr(C)]` slice DST is laid out [just like sized `#[repr(C)]`
/// types][repr-c-structs], but the presenence of a variable-length field
/// types][repr-c-structs], but the presence of a variable-length field
/// introduces the possibility of *dynamic padding*. In particular, it may be
/// necessary to add trailing padding *after* the trailing slice field in order
/// to satisfy the outer type's alignment, and the amount of padding required
Expand Down
4 changes: 2 additions & 2 deletions src/pointer/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ mod _external {
/// referent of a `Ptr<T, I: Invariants<Validity = V>>`. Since this copy
/// does not change `I::Validity` or `T`, `S(T, I::Validity)` is also
/// unchanged.
///
///
/// We are required to guarantee that the referents of the original `Ptr`
/// and of the copy (which, of course, are actually the same since they
/// live in the same byte address range) both remain in the set `S(T,
Expand Down Expand Up @@ -815,7 +815,7 @@ mod _transitions {
// contains a bit-valid instance of `T`. By `T:
// TryTransmuteFromPtr<T, I::Aliasing, I::Validity, Valid>`, so
// long as `self`'s referent conforms to the `Valid` validity
// for `T` (which we just confired), then this transmute is
// for `T` (which we just confirmed), then this transmute is
// sound.
Ok(unsafe { self.assume_valid() })
} else {
Expand Down
4 changes: 2 additions & 2 deletions src/ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,7 @@ where
let b = unsafe { r.as_byte_slice() };

// SAFETY: By postcondition on `as_byte_slice`, we know that `b` is a
// valid size and ailgnment for `T`. By safety invariant on `ByteSlice`,
// valid size and alignment for `T`. By safety invariant on `ByteSlice`,
// we know that this is preserved via `.deref()`. Because `T:
// FromBytes`, it is sound to interpret these bytes as a `T`.
unsafe { ptr::read(b.deref().as_ptr().cast::<T>()) }
Expand All @@ -741,7 +741,7 @@ where
let b = unsafe { r.as_byte_slice_mut() };

// SAFETY: By postcondition on `as_byte_slice_mut`, we know that `b` is
// a valid size and ailgnment for `T`. By safety invariant on
// a valid size and alignment for `T`. By safety invariant on
// `ByteSlice`, we know that this is preserved via `.deref()`. Writing
// `t` to the buffer will allow all of the bytes of `t` to be accessed
// as a `[u8]`, but because `T: IntoBytes`, we know that this is sound.
Expand Down
12 changes: 9 additions & 3 deletions src/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,19 @@ impl<T: ?Sized> Default for SendSyncPhantomData<T> {
}

impl<T: ?Sized> PartialEq for SendSyncPhantomData<T> {
fn eq(&self, other: &Self) -> bool {
self.0.eq(&other.0)
fn eq(&self, _other: &Self) -> bool {
true
}
}

impl<T: ?Sized> Eq for SendSyncPhantomData<T> {}

impl<T: ?Sized> Clone for SendSyncPhantomData<T> {
fn clone(&self) -> Self {
SendSyncPhantomData(PhantomData)
}
}

pub(crate) trait AsAddress {
fn addr(self) -> usize;
}
Expand Down Expand Up @@ -281,7 +287,7 @@ pub(crate) const unsafe fn transmute_unchecked<Src, Dst>(src: Src) -> Dst {
// SAFETY: Since `Transmute<Src, Dst>` is `#[repr(C)]`, its `src` and `dst`
// fields both start at the same offset and the types of those fields are
// transparent wrappers around `Src` and `Dst` [1]. Consequently,
// initializng `Transmute` with with `src` and then reading out `dst` is
// initializing `Transmute` with with `src` and then reading out `dst` is
// equivalent to transmuting from `Src` to `Dst` [2]. Transmuting from `src`
// to `Dst` is valid because — by contract on the caller — `src` is a valid
// instance of `Dst`.
Expand Down
Loading