mod inner;
#[doc(hidden)]
pub mod invariant;
mod ptr;
mod transmute;
#[doc(hidden)]
pub use {inner::PtrInner, transmute::*};
#[doc(hidden)]
pub use {
invariant::{BecauseExclusive, BecauseImmutable, Read},
ptr::Ptr,
};
pub type Maybe<'a, T, Aliasing = invariant::Shared, Alignment = invariant::Unaligned> =
Ptr<'a, T, (Aliasing, Alignment, invariant::Initialized)>;
pub(crate) fn is_zeroed<T, I>(ptr: Ptr<'_, T, I>) -> bool
where
T: crate::Immutable + crate::KnownLayout,
I: invariant::Invariants<Validity = invariant::Initialized>,
I::Aliasing: invariant::Reference,
{
ptr.as_bytes::<BecauseImmutable>().as_ref().iter().all(|&byte| byte == 0)
}
#[doc(hidden)]
pub mod cast {
use core::{marker::PhantomData, mem};
use crate::{
layout::{SizeInfo, TrailingSliceLayout},
HasField, KnownLayout, PtrInner,
};
pub unsafe trait Project<Src: ?Sized, Dst: ?Sized> {
fn project(src: PtrInner<'_, Src>) -> *mut Dst;
}
pub unsafe trait Cast<Src: ?Sized, Dst: ?Sized>: Project<Src, Dst> {}
#[derive(Default, Copy, Clone)]
#[allow(missing_debug_implementations)]
pub struct IdCast;
unsafe impl<T: ?Sized> Project<T, T> for IdCast {
#[inline(always)]
fn project(src: PtrInner<'_, T>) -> *mut T {
src.as_ptr()
}
}
unsafe impl<T: ?Sized> Cast<T, T> for IdCast {}
#[allow(missing_debug_implementations, missing_copy_implementations)]
pub enum CastSized {}
unsafe impl<Src, Dst> Project<Src, Dst> for CastSized {
#[inline(always)]
fn project(src: PtrInner<'_, Src>) -> *mut Dst {
static_assert!(Src, Dst => mem::size_of::<Src>() >= mem::size_of::<Dst>());
src.as_ptr().cast::<Dst>()
}
}
unsafe impl<Src, Dst> Cast<Src, Dst> for CastSized {}
#[allow(missing_debug_implementations, missing_copy_implementations)]
pub enum CastUnsized {}
unsafe impl<Src, Dst> Project<Src, Dst> for CastUnsized
where
Src: ?Sized + KnownLayout,
Dst: ?Sized + KnownLayout<PointerMetadata = Src::PointerMetadata>,
{
#[inline(always)]
fn project(src: PtrInner<'_, Src>) -> *mut Dst {
static_assert!(Src: ?Sized + KnownLayout, Dst: ?Sized + KnownLayout => {
let t = <Src as KnownLayout>::LAYOUT;
let u = <Dst as KnownLayout>::LAYOUT;
t.align.get() >= u.align.get() && match (t.size_info, u.size_info) {
(SizeInfo::Sized { size: t }, SizeInfo::Sized { size: u }) => t == u,
(
SizeInfo::SliceDst(TrailingSliceLayout { offset: t_offset, elem_size: t_elem_size }),
SizeInfo::SliceDst(TrailingSliceLayout { offset: u_offset, elem_size: u_elem_size })
) => t_offset == u_offset && t_elem_size == u_elem_size,
_ => false,
}
});
let metadata = Src::pointer_to_metadata(src.as_ptr());
Dst::raw_from_ptr_len(src.as_non_null().cast::<u8>(), metadata).as_ptr()
}
}
unsafe impl<Src, Dst> Cast<Src, Dst> for CastUnsized
where
Src: ?Sized + KnownLayout,
Dst: ?Sized + KnownLayout<PointerMetadata = Src::PointerMetadata>,
{
}
#[allow(missing_debug_implementations, missing_copy_implementations)]
pub struct Projection<F: ?Sized, const VARIANT_ID: i128, const FIELD_ID: i128> {
_never: core::convert::Infallible,
_phantom: PhantomData<F>,
}
unsafe impl<T: ?Sized, F, const VARIANT_ID: i128, const FIELD_ID: i128> Project<T, T::Type>
for Projection<F, VARIANT_ID, FIELD_ID>
where
T: HasField<F, VARIANT_ID, FIELD_ID>,
{
#[inline(always)]
fn project(src: PtrInner<'_, T>) -> *mut T::Type {
T::project(src)
}
}
#[allow(missing_debug_implementations)]
pub struct TransitiveProject<U: ?Sized, TU, UV> {
_never: core::convert::Infallible,
_projections: PhantomData<(TU, UV)>,
_u: PhantomData<U>,
}
unsafe impl<T, U, V, TU, UV> Project<T, V> for TransitiveProject<U, TU, UV>
where
T: ?Sized,
U: ?Sized,
V: ?Sized,
TU: Project<T, U>,
UV: Project<U, V>,
{
#[inline(always)]
fn project(t: PtrInner<'_, T>) -> *mut V {
t.project::<_, TU>().project::<_, UV>().as_ptr()
}
}
unsafe impl<T, U, V, TU, UV> Cast<T, V> for TransitiveProject<U, TU, UV>
where
T: ?Sized,
U: ?Sized,
V: ?Sized,
TU: Cast<T, U>,
UV: Cast<U, V>,
{
}
pub(crate) struct AsBytesCast;
unsafe impl<T: ?Sized + KnownLayout> Project<T, [u8]> for AsBytesCast {
#[inline(always)]
fn project(src: PtrInner<'_, T>) -> *mut [u8] {
let bytes = match T::size_of_val_raw(src.as_non_null()) {
Some(bytes) => bytes,
None => unsafe { core::hint::unreachable_unchecked() },
};
core::ptr::slice_from_raw_parts_mut(src.as_ptr().cast::<u8>(), bytes)
}
}
unsafe impl<T: ?Sized + KnownLayout> Cast<T, [u8]> for AsBytesCast {}
}