|
9 | 9 | use core::{fmt, hash::Hash}; |
10 | 10 |
|
11 | 11 | use super::*; |
| 12 | +use crate::pointer::{invariant::Valid, SizeEq, TransmuteFrom}; |
12 | 13 |
|
13 | 14 | /// A type with no alignment requirement. |
14 | 15 | /// |
@@ -594,6 +595,162 @@ impl<T: ?Sized + KnownLayout> fmt::Debug for MaybeUninit<T> { |
594 | 595 | } |
595 | 596 | } |
596 | 597 |
|
| 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 | + |
597 | 754 | #[cfg(test)] |
598 | 755 | mod tests { |
599 | 756 | use core::panic::AssertUnwindSafe; |
|
0 commit comments