Skip to content

Commit 3c09949

Browse files
committed
[WIP] ReadOnly
gherrit-pr-id: Gbe8d7edd150d80731c79815685c596ed88460ae7
1 parent 4ef287c commit 3c09949

2 files changed

Lines changed: 229 additions & 1 deletion

File tree

src/pointer/mod.rs

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,11 @@ where
4141

4242
#[doc(hidden)]
4343
pub mod cast {
44-
use core::{marker::PhantomData, mem};
44+
use core::{
45+
marker::PhantomData,
46+
mem::{self, MaybeUninit},
47+
num::Wrapping,
48+
};
4549

4650
use crate::{
4751
layout::{SizeInfo, TrailingSliceLayout},
@@ -290,6 +294,73 @@ pub mod cast {
290294
}
291295
}
292296

297+
/// TODO
298+
///
299+
/// # Safety
300+
///
301+
/// TODO
302+
pub unsafe trait Wrapped {
303+
type Unwrapped: ?Sized;
304+
type CastToUnwrapped: CastExact<Self, Self::Unwrapped>;
305+
type CastFromUnwrapped: CastExact<Self::Unwrapped, Self>;
306+
}
307+
308+
/// TODO
309+
///
310+
/// # Safety
311+
///
312+
/// TODO
313+
pub unsafe trait HasWrappedField<F: ?Sized>: Wrapped {
314+
type WrappedField: ?Sized + Wrapped<Unwrapped = F>;
315+
}
316+
317+
// SAFETY: TODO
318+
unsafe impl<T> Wrapped for MaybeUninit<T> {
319+
type Unwrapped = T;
320+
type CastToUnwrapped = CastSizedExact;
321+
type CastFromUnwrapped = CastSizedExact;
322+
}
323+
324+
// SAFETY: TODO
325+
unsafe impl<T, F> HasWrappedField<F> for MaybeUninit<T> {
326+
type WrappedField = MaybeUninit<F>;
327+
}
328+
329+
// SAFETY: TODO
330+
unsafe impl<T> Wrapped for Wrapping<T> {
331+
type Unwrapped = T;
332+
type CastToUnwrapped = CastSizedExact;
333+
type CastFromUnwrapped = CastSizedExact;
334+
}
335+
336+
// SAFETY: TODO
337+
unsafe impl<T, F> HasWrappedField<F> for Wrapping<T> {
338+
type WrappedField = Wrapping<F>;
339+
}
340+
341+
#[allow(missing_debug_implementations, missing_copy_implementations)]
342+
pub struct WrappedProjection<W: ?Sized, F, const VARIANT_ID: i128, const FIELD_ID: i128> {
343+
_never: core::convert::Infallible,
344+
_phantom: PhantomData<(F, W)>,
345+
}
346+
347+
// SAFETY: TODO
348+
unsafe impl<W: ?Sized, F, const VARIANT_ID: i128, const FIELD_ID: i128>
349+
Project<W, W::WrappedField> for WrappedProjection<W, F, VARIANT_ID, FIELD_ID>
350+
where
351+
W: Wrapped
352+
+ HasWrappedField<<<W as Wrapped>::Unwrapped as HasField<F, VARIANT_ID, FIELD_ID>>::Type>,
353+
W::Unwrapped: HasField<F, VARIANT_ID, FIELD_ID>,
354+
{
355+
#[inline(always)]
356+
fn project_inner(src: PtrInner<'_, W>) -> *mut W::WrappedField {
357+
src.project::<_, W::CastToUnwrapped>()
358+
.project::<_, Projection<F, VARIANT_ID, FIELD_ID>>()
359+
.project::<_, <W::WrappedField as Wrapped>::CastFromUnwrapped>()
360+
.as_ptr()
361+
}
362+
}
363+
293364
/// A transitive sequence of projections.
294365
///
295366
/// Given `TU: Project` and `UV: Project`, `TransitiveProject<_, TU, UV>` is

src/wrappers.rs

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use core::{fmt, hash::Hash};
1010

1111
use super::*;
12+
use crate::pointer::{invariant::Valid, SizeEq, TransmuteFrom};
1213

1314
/// A type with no alignment requirement.
1415
///
@@ -594,6 +595,162 @@ impl<T: ?Sized + KnownLayout> fmt::Debug for MaybeUninit<T> {
594595
}
595596
}
596597

598+
pub use read_only_def::*;
599+
mod read_only_def {
600+
use super::*;
601+
602+
/// A read-only wrapper.
603+
///
604+
/// A `ReadOnly<T>` disables any interior mutability in `T`, ensuring that
605+
/// a `&ReadOnly<T>` is genuinely read-only. Thus, `ReadOnly<T>` is
606+
/// [`Immutable`][immutable] regardless of whether `T` is.
607+
///
608+
/// Note that `&mut ReadOnly<T>` still permits mutation – the read-only
609+
/// property only applies to shared references.
610+
///
611+
/// [immutable]: crate::Immutable
612+
#[cfg_attr(any(feature = "derive", test), derive(FromBytes, IntoBytes, Unaligned))]
613+
#[repr(transparent)]
614+
pub struct ReadOnly<T: ?Sized> {
615+
// INVARIANT: `inner` is never mutated through a `&ReadOnly<T>`
616+
// reference.
617+
inner: T,
618+
}
619+
620+
impl<T> ReadOnly<T> {
621+
/// Creates a new `ReadOnly`.
622+
#[inline(always)]
623+
pub const fn new(t: T) -> ReadOnly<T> {
624+
ReadOnly { inner: t }
625+
}
626+
}
627+
628+
impl<T: ?Sized> ReadOnly<T> {
629+
#[inline(always)]
630+
pub(crate) const fn as_mut(r: &mut ReadOnly<T>) -> &mut T {
631+
// SAFETY: `r: &mut ReadOnly`, so this doesn't violate the invariant
632+
// that `inner` is never mutated through a `&ReadOnly<T>` reference.
633+
&mut r.inner
634+
}
635+
636+
/// # Safety
637+
///
638+
/// The caller promises not to mutate the referent (i.e., via interior
639+
/// mutation).
640+
pub(crate) const unsafe fn as_ref_unchecked(r: &ReadOnly<T>) -> &T {
641+
// SAFETY: The caller promises not to mutate the referent.
642+
&r.inner
643+
}
644+
}
645+
}
646+
647+
// SAFETY: `ReadOnly<T>` is a `#[repr(transparent)` wrapper around `T`.
648+
const _: () = unsafe {
649+
unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T)] ReadOnly<T>);
650+
};
651+
652+
// Unused when `feature = "derive"`.
653+
#[allow(unused_unsafe)]
654+
// SAFETY:
655+
// - `ReadOnly<T>` has the same alignment as `T`, and so it is `Unaligned`
656+
// exactly when `T` is as well.
657+
// - `ReadOnly<T>` has the same bit validity as `T`, and so it is `FromZeros`,
658+
// `FromBytes`, or `IntoBytes` exactly when `T` is as well.
659+
// - `TryFromBytes`: `ReadOnly<T>` has the same the same bit validity as `T`, so
660+
// `T::is_bit_valid` is a sound implementation of `is_bit_valid`.
661+
const _: () = unsafe {
662+
impl_or_verify!(T: ?Sized + Unaligned => Unaligned for ReadOnly<T>);
663+
impl_or_verify!(
664+
T: ?Sized + TryFromBytes => TryFromBytes for ReadOnly<T>;
665+
|c| T::is_bit_valid(c.transmute::<_, _, BecauseImmutable>())
666+
);
667+
impl_or_verify!(T: ?Sized + FromZeros => FromZeros for ReadOnly<T>);
668+
impl_or_verify!(T: ?Sized + FromBytes => FromBytes for ReadOnly<T>);
669+
impl_or_verify!(T: ?Sized + IntoBytes => IntoBytes for ReadOnly<T>);
670+
};
671+
672+
// SAFETY: By invariant, `inner` is never mutated through a `&ReadOnly<T>`
673+
// reference.
674+
const _: () = unsafe {
675+
unsafe_impl!(T: ?Sized => Immutable for ReadOnly<T>);
676+
};
677+
678+
const _: () = {
679+
use crate::pointer::cast::CastExact;
680+
681+
// SAFETY: `ReadOnly<T>` has the same layout as `T`.
682+
define_cast!(unsafe { pub CastFromReadOnly<T: ?Sized> = ReadOnly<T> => T});
683+
// SAFETY: `ReadOnly<T>` has the same layout as `T`.
684+
unsafe impl<T: ?Sized> CastExact<ReadOnly<T>, T> for CastFromReadOnly {}
685+
// SAFETY: `ReadOnly<T>` has the same layout as `T`.
686+
define_cast!(unsafe { pub CastToReadOnly<T: ?Sized> = T => ReadOnly<T>});
687+
// SAFETY: `ReadOnly<T>` has the same layout as `T`.
688+
unsafe impl<T: ?Sized> CastExact<T, ReadOnly<T>> for CastToReadOnly {}
689+
690+
impl<T: ?Sized> SizeEq<ReadOnly<T>> for T {
691+
type CastFrom = CastFromReadOnly;
692+
}
693+
694+
impl<T: ?Sized> SizeEq<T> for ReadOnly<T> {
695+
type CastFrom = CastToReadOnly;
696+
}
697+
698+
// SAFETY: TODO
699+
unsafe impl<T: ?Sized> crate::pointer::cast::Wrapped for ReadOnly<T> {
700+
type Unwrapped = T;
701+
type CastToUnwrapped = CastFromReadOnly;
702+
type CastFromUnwrapped = CastToReadOnly;
703+
}
704+
705+
// SAFETY: TODO
706+
unsafe impl<T: ?Sized, F: ?Sized> crate::pointer::cast::HasWrappedField<F> for ReadOnly<T> {
707+
type WrappedField = ReadOnly<F>;
708+
}
709+
};
710+
711+
// SAFETY: `ReadOnly<T>` is a `#[repr(transparent)]` wrapper around `T`, and so
712+
// it has the same bit validity as `T`.
713+
unsafe impl<T: ?Sized> TransmuteFrom<T, Valid, Valid> for ReadOnly<T> {}
714+
715+
// SAFETY: `ReadOnly<T>` is a `#[repr(transparent)]` wrapper around `T`, and so
716+
// it has the same bit validity as `T`.
717+
unsafe impl<T: ?Sized> TransmuteFrom<ReadOnly<T>, Valid, Valid> for T {}
718+
719+
impl<'a, T: ?Sized + Immutable> From<&'a T> for &'a ReadOnly<T> {
720+
#[inline(always)]
721+
fn from(t: &'a T) -> &'a ReadOnly<T> {
722+
let ro = Ptr::from_ref(t).transmute::<_, _, (_, _)>();
723+
// SAFETY: `ReadOnly<T>` has the same alignment as `T`, and
724+
// `Ptr::from_ref` produces an aligned `Ptr`.
725+
let ro = unsafe { ro.assume_alignment() };
726+
ro.as_ref()
727+
}
728+
}
729+
730+
impl<T: ?Sized + Immutable> Deref for ReadOnly<T> {
731+
type Target = T;
732+
733+
#[inline(always)]
734+
fn deref(&self) -> &Self::Target {
735+
// SAFETY: By `T: Immutable`, `&T` doesn't permit interior mutation.
736+
unsafe { ReadOnly::as_ref_unchecked(self) }
737+
}
738+
}
739+
740+
impl<T: ?Sized + Immutable> DerefMut for ReadOnly<T> {
741+
#[inline(always)]
742+
fn deref_mut(&mut self) -> &mut Self::Target {
743+
ReadOnly::as_mut(self)
744+
}
745+
}
746+
747+
impl<T: ?Sized + Immutable + Debug> Debug for ReadOnly<T> {
748+
#[inline(always)]
749+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
750+
self.deref().fmt(f)
751+
}
752+
}
753+
597754
#[cfg(test)]
598755
mod tests {
599756
use core::panic::AssertUnwindSafe;

0 commit comments

Comments
 (0)