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
73 changes: 72 additions & 1 deletion src/pointer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@ where

#[doc(hidden)]
pub mod cast {
use core::{marker::PhantomData, mem};
use core::{
marker::PhantomData,
mem::{self, MaybeUninit},
num::Wrapping,
};

use crate::{
layout::{SizeInfo, TrailingSliceLayout},
Expand Down Expand Up @@ -290,6 +294,73 @@ pub mod cast {
}
}

/// TODO
///
/// # Safety
///
/// TODO
pub unsafe trait Wrapped {
type Unwrapped: ?Sized;
type CastToUnwrapped: CastExact<Self, Self::Unwrapped>;
type CastFromUnwrapped: CastExact<Self::Unwrapped, Self>;
}

/// TODO
///
/// # Safety
///
/// TODO
pub unsafe trait HasWrappedField<F: ?Sized>: Wrapped {
type WrappedField: ?Sized + Wrapped<Unwrapped = F>;
}

// SAFETY: TODO
unsafe impl<T> Wrapped for MaybeUninit<T> {
type Unwrapped = T;
type CastToUnwrapped = CastSizedExact;
type CastFromUnwrapped = CastSizedExact;
}

// SAFETY: TODO
unsafe impl<T, F> HasWrappedField<F> for MaybeUninit<T> {
type WrappedField = MaybeUninit<F>;
}

// SAFETY: TODO
unsafe impl<T> Wrapped for Wrapping<T> {
type Unwrapped = T;
type CastToUnwrapped = CastSizedExact;
type CastFromUnwrapped = CastSizedExact;
}

// SAFETY: TODO
unsafe impl<T, F> HasWrappedField<F> for Wrapping<T> {
type WrappedField = Wrapping<F>;
}

#[allow(missing_debug_implementations, missing_copy_implementations)]
pub struct WrappedProjection<W: ?Sized, F, const VARIANT_ID: i128, const FIELD_ID: i128> {
_never: core::convert::Infallible,
_phantom: PhantomData<(F, W)>,
}

// SAFETY: TODO
unsafe impl<W: ?Sized, F, const VARIANT_ID: i128, const FIELD_ID: i128>
Project<W, W::WrappedField> for WrappedProjection<W, F, VARIANT_ID, FIELD_ID>
where
W: Wrapped
+ HasWrappedField<<<W as Wrapped>::Unwrapped as HasField<F, VARIANT_ID, FIELD_ID>>::Type>,
W::Unwrapped: HasField<F, VARIANT_ID, FIELD_ID>,
{
#[inline(always)]
fn project_inner(src: PtrInner<'_, W>) -> *mut W::WrappedField {
src.project::<_, W::CastToUnwrapped>()
.project::<_, Projection<F, VARIANT_ID, FIELD_ID>>()
.project::<_, <W::WrappedField as Wrapped>::CastFromUnwrapped>()
.as_ptr()
}
}

/// A transitive sequence of projections.
///
/// Given `TU: Project` and `UV: Project`, `TransitiveProject<_, TU, UV>` is
Expand Down
157 changes: 157 additions & 0 deletions src/wrappers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use core::{fmt, hash::Hash};

use super::*;
use crate::pointer::{invariant::Valid, SizeEq, TransmuteFrom};

/// A type with no alignment requirement.
///
Expand Down Expand Up @@ -594,6 +595,162 @@ impl<T: ?Sized + KnownLayout> fmt::Debug for MaybeUninit<T> {
}
}

pub use read_only_def::*;
mod read_only_def {
use super::*;

/// A read-only wrapper.
///
/// A `ReadOnly<T>` disables any interior mutability in `T`, ensuring that
/// a `&ReadOnly<T>` is genuinely read-only. Thus, `ReadOnly<T>` is
/// [`Immutable`][immutable] regardless of whether `T` is.
///
/// Note that `&mut ReadOnly<T>` still permits mutation – the read-only
/// property only applies to shared references.
///
/// [immutable]: crate::Immutable
#[cfg_attr(any(feature = "derive", test), derive(FromBytes, IntoBytes, Unaligned))]
#[repr(transparent)]
pub struct ReadOnly<T: ?Sized> {
// INVARIANT: `inner` is never mutated through a `&ReadOnly<T>`
// reference.
inner: T,
}

impl<T> ReadOnly<T> {
/// Creates a new `ReadOnly`.
#[inline(always)]
pub const fn new(t: T) -> ReadOnly<T> {
ReadOnly { inner: t }
}
}

impl<T: ?Sized> ReadOnly<T> {
#[inline(always)]
pub(crate) const fn as_mut(r: &mut ReadOnly<T>) -> &mut T {
// SAFETY: `r: &mut ReadOnly`, so this doesn't violate the invariant
// that `inner` is never mutated through a `&ReadOnly<T>` reference.
&mut r.inner
}

/// # Safety
///
/// The caller promises not to mutate the referent (i.e., via interior
/// mutation).
pub(crate) const unsafe fn as_ref_unchecked(r: &ReadOnly<T>) -> &T {
// SAFETY: The caller promises not to mutate the referent.
&r.inner
}
}
}

// SAFETY: `ReadOnly<T>` is a `#[repr(transparent)` wrapper around `T`.
const _: () = unsafe {
unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T)] ReadOnly<T>);
};

// Unused when `feature = "derive"`.
#[allow(unused_unsafe)]
// SAFETY:
// - `ReadOnly<T>` has the same alignment as `T`, and so it is `Unaligned`
// exactly when `T` is as well.
// - `ReadOnly<T>` has the same bit validity as `T`, and so it is `FromZeros`,
// `FromBytes`, or `IntoBytes` exactly when `T` is as well.
// - `TryFromBytes`: `ReadOnly<T>` has the same the same bit validity as `T`, so
// `T::is_bit_valid` is a sound implementation of `is_bit_valid`.
const _: () = unsafe {
impl_or_verify!(T: ?Sized + Unaligned => Unaligned for ReadOnly<T>);
impl_or_verify!(
T: ?Sized + TryFromBytes => TryFromBytes for ReadOnly<T>;
|c| T::is_bit_valid(c.transmute::<_, _, BecauseImmutable>())
);
impl_or_verify!(T: ?Sized + FromZeros => FromZeros for ReadOnly<T>);
impl_or_verify!(T: ?Sized + FromBytes => FromBytes for ReadOnly<T>);
impl_or_verify!(T: ?Sized + IntoBytes => IntoBytes for ReadOnly<T>);
};

// SAFETY: By invariant, `inner` is never mutated through a `&ReadOnly<T>`
// reference.
const _: () = unsafe {
unsafe_impl!(T: ?Sized => Immutable for ReadOnly<T>);
};

const _: () = {
use crate::pointer::cast::CastExact;

// SAFETY: `ReadOnly<T>` has the same layout as `T`.
define_cast!(unsafe { pub CastFromReadOnly<T: ?Sized> = ReadOnly<T> => T});
// SAFETY: `ReadOnly<T>` has the same layout as `T`.
unsafe impl<T: ?Sized> CastExact<ReadOnly<T>, T> for CastFromReadOnly {}
// SAFETY: `ReadOnly<T>` has the same layout as `T`.
define_cast!(unsafe { pub CastToReadOnly<T: ?Sized> = T => ReadOnly<T>});
// SAFETY: `ReadOnly<T>` has the same layout as `T`.
unsafe impl<T: ?Sized> CastExact<T, ReadOnly<T>> for CastToReadOnly {}

impl<T: ?Sized> SizeEq<ReadOnly<T>> for T {
type CastFrom = CastFromReadOnly;
}

impl<T: ?Sized> SizeEq<T> for ReadOnly<T> {
type CastFrom = CastToReadOnly;
}

// SAFETY: TODO
unsafe impl<T: ?Sized> crate::pointer::cast::Wrapped for ReadOnly<T> {
type Unwrapped = T;
type CastToUnwrapped = CastFromReadOnly;
type CastFromUnwrapped = CastToReadOnly;
}

// SAFETY: TODO
unsafe impl<T: ?Sized, F: ?Sized> crate::pointer::cast::HasWrappedField<F> for ReadOnly<T> {
type WrappedField = ReadOnly<F>;
}
};

// SAFETY: `ReadOnly<T>` is a `#[repr(transparent)]` wrapper around `T`, and so
// it has the same bit validity as `T`.
unsafe impl<T: ?Sized> TransmuteFrom<T, Valid, Valid> for ReadOnly<T> {}

// SAFETY: `ReadOnly<T>` is a `#[repr(transparent)]` wrapper around `T`, and so
// it has the same bit validity as `T`.
unsafe impl<T: ?Sized> TransmuteFrom<ReadOnly<T>, Valid, Valid> for T {}

impl<'a, T: ?Sized + Immutable> From<&'a T> for &'a ReadOnly<T> {
#[inline(always)]
fn from(t: &'a T) -> &'a ReadOnly<T> {
let ro = Ptr::from_ref(t).transmute::<_, _, (_, _)>();
// SAFETY: `ReadOnly<T>` has the same alignment as `T`, and
// `Ptr::from_ref` produces an aligned `Ptr`.
let ro = unsafe { ro.assume_alignment() };
ro.as_ref()
}
}

impl<T: ?Sized + Immutable> Deref for ReadOnly<T> {
type Target = T;

#[inline(always)]
fn deref(&self) -> &Self::Target {
// SAFETY: By `T: Immutable`, `&T` doesn't permit interior mutation.
unsafe { ReadOnly::as_ref_unchecked(self) }
}
}

impl<T: ?Sized + Immutable> DerefMut for ReadOnly<T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
ReadOnly::as_mut(self)
}
}

impl<T: ?Sized + Immutable + Debug> Debug for ReadOnly<T> {
#[inline(always)]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.deref().fmt(f)
}
}

#[cfg(test)]
mod tests {
use core::panic::AssertUnwindSafe;
Expand Down
Loading