Move the FooInOption traits into their own files for easier organization.

This commit is contained in:
Lokathor 2022-07-02 15:21:11 -06:00
parent abe55e525e
commit 1f265a9e0d
5 changed files with 107 additions and 64 deletions

View File

@ -90,9 +90,13 @@ mod internal;
mod zeroable;
pub use zeroable::*;
mod zeroable_in_option;
pub use zeroable_in_option::*;
mod pod;
pub use pod::*;
mod pod_in_option;
pub use pod_in_option::*;
mod no_uninit;
pub use no_uninit::*;
@ -108,7 +112,8 @@ pub use transparent::*;
#[cfg(feature = "derive")]
pub use bytemuck_derive::{
AnyBitPattern, Contiguous, CheckedBitPattern, NoUninit, Pod, TransparentWrapper, Zeroable,
AnyBitPattern, CheckedBitPattern, Contiguous, NoUninit, Pod,
TransparentWrapper, Zeroable,
};
/// The things that can go wrong when casting between [`Pod`] data forms.
@ -185,7 +190,9 @@ pub fn from_bytes_mut<T: NoUninit + AnyBitPattern>(s: &mut [u8]) -> &mut T {
/// ## Failure
/// * If the `bytes` length is not equal to `size_of::<T>()`.
#[inline]
pub fn try_pod_read_unaligned<T: AnyBitPattern>(bytes: &[u8]) -> Result<T, PodCastError> {
pub fn try_pod_read_unaligned<T: AnyBitPattern>(
bytes: &[u8],
) -> Result<T, PodCastError> {
unsafe { internal::try_pod_read_unaligned(bytes) }
}
@ -238,7 +245,9 @@ pub fn cast<A: NoUninit, B: AnyBitPattern>(a: A) -> B {
///
/// This is [`try_cast_mut`] but will panic on error.
#[inline]
pub fn cast_mut<A: NoUninit + AnyBitPattern, B: NoUninit + AnyBitPattern>(a: &mut A) -> &mut B {
pub fn cast_mut<A: NoUninit + AnyBitPattern, B: NoUninit + AnyBitPattern>(
a: &mut A,
) -> &mut B {
unsafe { internal::cast_mut(a) }
}
@ -268,19 +277,29 @@ pub fn cast_slice<A: NoUninit, B: AnyBitPattern>(a: &[A]) -> &[B] {
///
/// This is [`try_cast_slice_mut`] but will panic on error.
#[inline]
pub fn cast_slice_mut<A: NoUninit + AnyBitPattern, B: NoUninit + AnyBitPattern>(a: &mut [A]) -> &mut [B] {
pub fn cast_slice_mut<
A: NoUninit + AnyBitPattern,
B: NoUninit + AnyBitPattern,
>(
a: &mut [A],
) -> &mut [B] {
unsafe { internal::cast_slice_mut(a) }
}
/// As `align_to`, but safe because of the [`Pod`] bound.
#[inline]
pub fn pod_align_to<T: NoUninit, U: AnyBitPattern>(vals: &[T]) -> (&[T], &[U], &[T]) {
pub fn pod_align_to<T: NoUninit, U: AnyBitPattern>(
vals: &[T],
) -> (&[T], &[U], &[T]) {
unsafe { vals.align_to::<U>() }
}
/// As `align_to_mut`, but safe because of the [`Pod`] bound.
#[inline]
pub fn pod_align_to_mut<T: NoUninit + AnyBitPattern, U: NoUninit + AnyBitPattern>(
pub fn pod_align_to_mut<
T: NoUninit + AnyBitPattern,
U: NoUninit + AnyBitPattern,
>(
vals: &mut [T],
) -> (&mut [T], &mut [U], &mut [T]) {
unsafe { vals.align_to_mut::<U>() }
@ -297,7 +316,9 @@ pub fn pod_align_to_mut<T: NoUninit + AnyBitPattern, U: NoUninit + AnyBitPattern
///
/// * If the types don't have the same size this fails.
#[inline]
pub fn try_cast<A: NoUninit, B: AnyBitPattern>(a: A) -> Result<B, PodCastError> {
pub fn try_cast<A: NoUninit, B: AnyBitPattern>(
a: A,
) -> Result<B, PodCastError> {
unsafe { internal::try_cast(a) }
}
@ -308,7 +329,9 @@ pub fn try_cast<A: NoUninit, B: AnyBitPattern>(a: A) -> Result<B, PodCastError>
/// * If the reference isn't aligned in the new type
/// * If the source type and target type aren't the same size.
#[inline]
pub fn try_cast_ref<A: NoUninit, B: AnyBitPattern>(a: &A) -> Result<&B, PodCastError> {
pub fn try_cast_ref<A: NoUninit, B: AnyBitPattern>(
a: &A,
) -> Result<&B, PodCastError> {
unsafe { internal::try_cast_ref(a) }
}
@ -316,7 +339,12 @@ pub fn try_cast_ref<A: NoUninit, B: AnyBitPattern>(a: &A) -> Result<&B, PodCastE
///
/// As [`try_cast_ref`], but `mut`.
#[inline]
pub fn try_cast_mut<A: NoUninit + AnyBitPattern, B: NoUninit + AnyBitPattern>(a: &mut A) -> Result<&mut B, PodCastError> {
pub fn try_cast_mut<
A: NoUninit + AnyBitPattern,
B: NoUninit + AnyBitPattern,
>(
a: &mut A,
) -> Result<&mut B, PodCastError> {
unsafe { internal::try_cast_mut(a) }
}
@ -336,7 +364,9 @@ pub fn try_cast_mut<A: NoUninit + AnyBitPattern, B: NoUninit + AnyBitPattern>(a:
/// * Similarly, you can't convert between a [ZST](https://doc.rust-lang.org/nomicon/exotic-sizes.html#zero-sized-types-zsts)
/// and a non-ZST.
#[inline]
pub fn try_cast_slice<A: NoUninit, B: AnyBitPattern>(a: &[A]) -> Result<&[B], PodCastError> {
pub fn try_cast_slice<A: NoUninit, B: AnyBitPattern>(
a: &[A],
) -> Result<&[B], PodCastError> {
unsafe { internal::try_cast_slice(a) }
}
@ -345,7 +375,10 @@ pub fn try_cast_slice<A: NoUninit, B: AnyBitPattern>(a: &[A]) -> Result<&[B], Po
///
/// As [`try_cast_slice`], but `&mut`.
#[inline]
pub fn try_cast_slice_mut<A: NoUninit + AnyBitPattern, B: NoUninit + AnyBitPattern>(
pub fn try_cast_slice_mut<
A: NoUninit + AnyBitPattern,
B: NoUninit + AnyBitPattern,
>(
a: &mut [A],
) -> Result<&mut [B], PodCastError> {
unsafe { internal::try_cast_slice_mut(a) }

View File

@ -18,21 +18,22 @@ use super::*;
/// [Infallible](core::convert::Infallible)).
/// * The type must allow any bit pattern (eg: no `bool` or `char`, which have
/// illegal bit patterns).
/// * The type must not contain any uninit (or padding) bytes, either in the middle or on
/// the end (eg: no `#[repr(C)] struct Foo(u8, u16)`, which has padding in the
/// middle, and also no `#[repr(C)] struct Foo(u16, u8)`, which has padding on
/// the end).
/// * The type must not contain any uninit (or padding) bytes, either in the
/// middle or on the end (eg: no `#[repr(C)] struct Foo(u8, u16)`, which has
/// padding in the middle, and also no `#[repr(C)] struct Foo(u16, u8)`, which
/// has padding on the end).
/// * The type needs to have all fields also be `Pod`.
/// * The type needs to be `repr(C)` or `repr(transparent)`. In the case of
/// `repr(C)`, the `packed` and `align` repr modifiers can be used as long as
/// all other rules end up being followed.
/// * It is disallowed for types to contain pointer types, `Cell`, `UnsafeCell`, atomics, and any
/// other forms of interior mutability.
/// * More precisely: A shared reference to the type must allow reads, and *only* reads. RustBelt's
/// separation logic is based on the notion that a type is allowed to define a sharing predicate,
/// its own invariant that must hold for shared references, and this predicate is the reasoning
/// that allow it to deal with atomic and cells etc. We require the sharing predicate to be
/// trivial and permit only read-only access.
/// * It is disallowed for types to contain pointer types, `Cell`, `UnsafeCell`,
/// atomics, and any other forms of interior mutability.
/// * More precisely: A shared reference to the type must allow reads, and
/// *only* reads. RustBelt's separation logic is based on the notion that a
/// type is allowed to define a sharing predicate, its own invariant that must
/// hold for shared references, and this predicate is the reasoning that allow
/// it to deal with atomic and cells etc. We require the sharing predicate to
/// be trivial and permit only read-only access.
pub unsafe trait Pod: Zeroable + Copy + 'static {}
unsafe impl Pod for () {}
@ -52,27 +53,6 @@ unsafe impl Pod for f32 {}
unsafe impl Pod for f64 {}
unsafe impl<T: Pod> Pod for Wrapping<T> {}
/// Trait for types which are [Pod](Pod) when wrapped in [Option](core::option::Option).
///
/// ## Safety
///
/// * `Option<T>` must uphold the same invariants as [Pod](Pod).
pub unsafe trait PodInOption: ZeroableInOption + Copy + 'static {}
unsafe impl<T: PodInOption> Pod for Option<T> {}
unsafe impl PodInOption for NonZeroI8 {}
unsafe impl PodInOption for NonZeroI16 {}
unsafe impl PodInOption for NonZeroI32 {}
unsafe impl PodInOption for NonZeroI64 {}
unsafe impl PodInOption for NonZeroI128 {}
unsafe impl PodInOption for NonZeroIsize {}
unsafe impl PodInOption for NonZeroU8 {}
unsafe impl PodInOption for NonZeroU16 {}
unsafe impl PodInOption for NonZeroU32 {}
unsafe impl PodInOption for NonZeroU64 {}
unsafe impl PodInOption for NonZeroU128 {}
unsafe impl PodInOption for NonZeroUsize {}
#[cfg(feature = "unsound_ptr_pod_impl")]
unsafe impl<T: 'static> Pod for *mut T {}
#[cfg(feature = "unsound_ptr_pod_impl")]

25
src/pod_in_option.rs Normal file
View File

@ -0,0 +1,25 @@
use super::*;
// Note(Lokathor): This is the neat part!!
unsafe impl<T: PodInOption> Pod for Option<T> {}
/// Trait for types which are [Pod](Pod) when wrapped in
/// [Option](core::option::Option).
///
/// ## Safety
///
/// * `Option<T>` must uphold the same invariants as [Pod](Pod).
pub unsafe trait PodInOption: ZeroableInOption + Copy + 'static {}
unsafe impl PodInOption for NonZeroI8 {}
unsafe impl PodInOption for NonZeroI16 {}
unsafe impl PodInOption for NonZeroI32 {}
unsafe impl PodInOption for NonZeroI64 {}
unsafe impl PodInOption for NonZeroI128 {}
unsafe impl PodInOption for NonZeroIsize {}
unsafe impl PodInOption for NonZeroU8 {}
unsafe impl PodInOption for NonZeroU16 {}
unsafe impl PodInOption for NonZeroU32 {}
unsafe impl PodInOption for NonZeroU64 {}
unsafe impl PodInOption for NonZeroU128 {}
unsafe impl PodInOption for NonZeroUsize {}

View File

@ -42,27 +42,6 @@ unsafe impl Zeroable for f32 {}
unsafe impl Zeroable for f64 {}
unsafe impl<T: Zeroable> Zeroable for Wrapping<T> {}
/// Trait for types which are [Zeroable](Zeroable) when wrapped in [Option](core::option::Option).
///
/// ## Safety
///
/// * `Option<T>` must uphold the same invariants as [Zeroable](Zeroable).
pub unsafe trait ZeroableInOption: Sized {}
unsafe impl<T: ZeroableInOption> Zeroable for Option<T> {}
unsafe impl ZeroableInOption for NonZeroI8 {}
unsafe impl ZeroableInOption for NonZeroI16 {}
unsafe impl ZeroableInOption for NonZeroI32 {}
unsafe impl ZeroableInOption for NonZeroI64 {}
unsafe impl ZeroableInOption for NonZeroI128 {}
unsafe impl ZeroableInOption for NonZeroIsize {}
unsafe impl ZeroableInOption for NonZeroU8 {}
unsafe impl ZeroableInOption for NonZeroU16 {}
unsafe impl ZeroableInOption for NonZeroU32 {}
unsafe impl ZeroableInOption for NonZeroU64 {}
unsafe impl ZeroableInOption for NonZeroU128 {}
unsafe impl ZeroableInOption for NonZeroUsize {}
unsafe impl<T> Zeroable for *mut T {}
unsafe impl<T> Zeroable for *const T {}
unsafe impl<T> ZeroableInOption for NonNull<T> {}

26
src/zeroable_in_option.rs Normal file
View File

@ -0,0 +1,26 @@
use super::*;
// Note(Lokathor): This is the neat part!!
unsafe impl<T: ZeroableInOption> Zeroable for Option<T> {}
/// Trait for types which are [Zeroable](Zeroable) when wrapped in
/// [Option](core::option::Option).
///
/// ## Safety
///
/// * `Option<YourType>` must uphold the same invariants as
/// [Zeroable](Zeroable).
pub unsafe trait ZeroableInOption: Sized {}
unsafe impl ZeroableInOption for NonZeroI8 {}
unsafe impl ZeroableInOption for NonZeroI16 {}
unsafe impl ZeroableInOption for NonZeroI32 {}
unsafe impl ZeroableInOption for NonZeroI64 {}
unsafe impl ZeroableInOption for NonZeroI128 {}
unsafe impl ZeroableInOption for NonZeroIsize {}
unsafe impl ZeroableInOption for NonZeroU8 {}
unsafe impl ZeroableInOption for NonZeroU16 {}
unsafe impl ZeroableInOption for NonZeroU32 {}
unsafe impl ZeroableInOption for NonZeroU64 {}
unsafe impl ZeroableInOption for NonZeroU128 {}
unsafe impl ZeroableInOption for NonZeroUsize {}