1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
use ::core::{
marker::PhantomData,
ops::{Deref, DerefMut},
};
use ::munge::{Destructure, Restructure};
use ::ptr_meta::Pointee;
use crate::{Frame, Metadata, Pointer, Region, RegionalAllocator, Slot};
/// A pointer which has its pointee in a specific memory region.
#[derive(Clone, Copy)]
pub struct In<P, R: Region> {
ptr: P,
region: PhantomData<R>,
}
impl<P: Pointer, R: Region> In<P, R>
where
P::Target: Pointee,
{
/// Creates a new `In` from a pointer.
pub fn new(ptr: P) -> Self
where
P: Within<R>,
{
// SAFETY: The pointee of `ptr` is must be located in `R` because `P`
// implements `Within<R>`.
unsafe { Self::new_unchecked(ptr) }
}
/// Creates a new `In` from a pointer.
///
/// # Safety
///
/// The pointee of `ptr` must be contained in `R`.
pub unsafe fn new_unchecked(ptr: P) -> Self {
Self {
ptr,
region: PhantomData,
}
}
/// Maps this `In` to another pointer in its region.
pub fn map<F, Q>(self, f: F) -> In<Q, R>
where
F: FnOnce(P) -> Q,
Q: Pointer + Within<R>,
Q::Target: Pointee,
{
In::new(f(Self::into_inner(self)))
}
/// Maps this `In` to another pointer in its region.
///
/// # Safety
///
/// The pointer returned by `f` must be completely contained in `R`.
pub unsafe fn map_unchecked<F, Q>(self, f: F) -> In<Q, R>
where
F: FnOnce(P) -> Q,
Q: Pointer,
Q::Target: Pointee,
{
let ptr = Self::into_inner(self);
// SAFETY: The caller has gauranteed that `R` completely contains the
// mapped pointer.
unsafe { In::new_unchecked(f(ptr)) }
}
/// Gets a raw `In` from this pointer.
pub fn as_raw(&self) -> In<*mut P::Target, R> {
// SAFETY: `self.ptr.deref_raw()` returns a pointer located in `R`.
// Calling `deref_raw` on that returned `*mut P::Target` returns the
// same pointer again because raw pointers `deref_raw` to themselves. So
// `self.ptr.deref_raw()` also returns a pointer in `R` when `deref_raw`
// is called on it.
unsafe { In::new_unchecked(self.ptr.target()) }
}
}
impl<P, R: Region> In<P, R> {
/// Unwraps an `In`, returning the underlying pointer.
pub fn into_inner(this: Self) -> P {
this.ptr
}
/// Returns a reference to the pointer of this `In`.
pub fn ptr(&self) -> &P {
&self.ptr
}
/// Returns a mutable reference to the pointer of this `In`.
///
/// # Safety
///
/// The pointer must not be mutated to point outside of `R`.
pub unsafe fn ptr_mut(&mut self) -> &mut P {
&mut self.ptr
}
}
impl<T: Pointee + ?Sized, A: RegionalAllocator> In<Frame<T, A>, A::Region>
where
<T as Pointee>::Metadata: Metadata<T>,
{
/// Returns a [`Slot`] of the internal contents.
pub fn slot(&'_ mut self) -> In<Slot<'_, T>, A::Region> {
// SAFETY: `slot` is wrapped in an `In` before being returned to prevent
// it from being pointed outside of `R`, and we don't mutate it to point
// elsewhere.
let slot = unsafe { self.ptr_mut().slot() };
// SAFETY: `slot` points to the same location as `self`, which points to
// a slot located in `R`. Therefore, `slot` must also point to a a slot
// located in `R`.
unsafe { In::new_unchecked(slot) }
}
}
impl<'a, T: Pointee + ?Sized, R: Region> In<Slot<'a, T>, R> {
/// Gets a mutable borrow from this slot.
pub fn as_mut<'b>(&'b mut self) -> In<Slot<'b, T>, R>
where
'a: 'b,
{
// SAFETY: The original and reborrowed slots are guaranteed to both
// point to the same memory. Since the original slot is guaranteed to be
// located in `R`, the reborrowed slot must also be located in `R`.
unsafe { In::new_unchecked(self.ptr.as_mut()) }
}
}
impl<P: Deref, R: Region> Deref for In<P, R> {
type Target = P::Target;
fn deref(&self) -> &Self::Target {
self.ptr().deref()
}
}
impl<P: DerefMut, R: Region> DerefMut for In<P, R> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.ptr.deref_mut()
}
}
/// A `Pointer` that may be restructured with `munge`.
///
/// # Safety
///
/// This type's `Destructure::underlying` implementation must return the same
/// pointer as `Pointer::target`.
pub unsafe trait RestructurablePointer: Destructure {}
// SAFETY:
// - `In<P, R>` is destructured in the same way as its inner pointer is, so its
// `Destructuring` type is `P::Underlying`.
// - `underlying` returns the underlying of the inner pointer, which is also
// guaranteed to be non-null, properly-aligned, and valid for reads.
unsafe impl<P: Destructure, R: Region> Destructure for In<P, R> {
type Underlying = P::Underlying;
type Destructuring = P::Destructuring;
fn underlying(&mut self) -> *mut Self::Underlying {
self.ptr.underlying()
}
}
type RsTarget<F, T> = <<F as Restructure<T>>::Restructured as Pointer>::Target;
// SAFETY: `restructure` returns a valid `In` created by restructuring using the
// inner pointer's restructuring. Because the inner pointer upholds its
// destructuring invariants, `In` does too.
unsafe impl<P, R: Region, U> Restructure<U> for In<P, R>
where
P: RestructurablePointer + Restructure<U>,
<P as Restructure<U>>::Restructured: Pointer,
RsTarget<P, U>: Pointee,
{
type Restructured = In<<P as Restructure<U>>::Restructured, R>;
unsafe fn restructure(&self, ptr: *mut U) -> Self::Restructured {
// SAFETY: The caller has guaranteed that `ptr` is a properly aligned
// pointer to a subfield of the pointer underlying `self`, which is the
// pointer underlying `self.ptr`.
let restructured = unsafe { self.ptr.restructure(ptr) };
// SAFETY: The restructured pointer must be a subfield of the original
// pointer's pointee, so it's necessarily located in the same region as
// the original as well. The safety requirements for
// `RestructurablePointer` require that the pointer returned from
// `Destructure::underlying` must be the same as the pointer returned
// from `deref_raw`, so it's not possible to return different pointers
// from each.
unsafe { In::new_unchecked(restructured) }
}
}
/// A pointer that knows where its target is located
///
/// # Safety
///
/// The `target` of the type must be located in `R`.
pub unsafe trait Within<R: Region>: Pointer {}