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 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
use core::{
alloc::{AllocError, Layout},
hash::Hash,
mem::MaybeUninit,
ptr::copy_nonoverlapping,
};
pub type Memory = [MaybeUninit<u8>];
/// Types which can be used to manage memory handles.
///
/// The behavior of this trait is refined by traits [`PinningStorage`],
/// [`MultipleStorage`], and [`SharedMutabilityStorage`].
pub unsafe trait Storage {
/// The handle which is used to access the stored memory.
///
/// (Removing `Send + Sync` is enticing, as it allows using `ptr::NonNull`.)
type Handle: Copy + Ord + Hash + Unpin + Send + Sync;
/// Allocate memory handle in this storage.
///
/// The handled memory is not initialized. Any existing handles are
/// invalidated.
///
/// (Do we want an `allocate_zeroed`?)
fn allocate(&mut self, layout: Layout) -> Result<Self::Handle, AllocError>;
/// Deallocate an object handle in this storage.
///
/// The handled memory is not required to be valid in any way. The handle is
/// invalidated.
///
/// # Safety
///
/// - The handle must have been created by this storage, and must not have
/// been invalidated.
/// - The layout must be the same as used to allocate the handle.
unsafe fn deallocate(&mut self, handle: Self::Handle, layout: Layout);
/// Resolve a memory handle in this storage to a reference.
///
/// # Safety
///
/// - The handle must have been created by this storage, and must not have
/// been invalidated.
/// - The layout must be the same as used to allocate the handle.
unsafe fn resolve(&self, handle: Self::Handle, layout: Layout) -> &Memory;
/// Resolve a memory handle in this storage to a mutable reference.
///
/// # Safety
///
/// - The handle must have been created by this storage, and must not have
/// been invalidated.
/// - The layout must be the same as used to allocate the handle.
unsafe fn resolve_mut(&mut self, handle: Self::Handle, layout: Layout) -> &mut Memory;
/// Grow a memory handle to a larger size.
///
/// If this function succeeds, then the old handle is invalidated and the
/// handled memory has been moved into the new handle. The new length is
/// uninitialized.
///
/// (Do we want a `grow_zeroed`?)
///
/// If this function fails, then the old handle is not invalidated and
/// still contains the memory in its state before calling this function.
///
/// # Safety
///
/// - The handle must have been created by this storage, and must not have
/// been invalidated.
/// - `old_layout` must be the same as used to allocate the handle.
/// - `new_layout.size() >= old_layout.size()`.
///
/// Note that `new_layout.align()` is not required to be the same as
/// `old_layout.align()`
unsafe fn grow(
&mut self,
handle: Self::Handle,
old_layout: Layout,
new_layout: Layout,
) -> Result<Self::Handle, AllocError>;
/// Shrink a memory handle to a smaller size.
///
/// If this function succeeds, then the old handle is invalidated and the
/// prefix of the handled memory has been moved into the new handle.
///
/// If this function fails, then the old handle is not invalidated and
/// still contains the memory in its state before calling this function.
///
/// # Safety
///
/// - The handle must have been created by this storage, and must not have
/// been invalidated.
/// - `old_layout` must be the same as used to allocate the handle.
/// - `new_layout.size() <= old_layout.size()`.
///
/// Note that `new_layout.align()` is not required to be the same as
/// `old_layout.align()`
unsafe fn shrink(
&mut self,
handle: Self::Handle,
old_layout: Layout,
new_layout: Layout,
) -> Result<Self::Handle, AllocError>;
}
/// A storage that allocates pinned memory handles.
///
/// Any memory allocated inside of this storage will not be moved nor reused
/// until [`deallocate`] is called on its handle. As such, an object in the
/// memory can be safely pinned.
///
/// [`deallocate`]: Storage::deallocate
pub unsafe trait PinningStorage: Storage {}
/// A storage that can manage multiple memory handles.
///
/// [`allocate`] no longer invalidates existing handles. You can `allocate`
/// multiple handles that are all valid at the same time. This does not change
/// the requirements of [`resolve`] or [`resolve_mut`]; only one pointer
/// returned from `resolve_mut` is valid at a time.
///
/// In addition, [`grow`] and [`shrink`] are implemented at least at least as
/// well as creating a new handle and copying over the old contents. (This is
/// provided by default impl.)
///
/// [`allocate`]: Storage::allocate
/// [`resolve`]: Storage::resolve
/// [`resolve_mut`]: Storage::resolve_mut
/// [`grow`]: Storage::grow
/// [`shrink`]: Storage::shrink
pub unsafe trait MultipleStorage: Storage {
/// Resolve memory handles in this storage to mutable references.
///
/// # Safety
///
/// - The handles must have been created by this storage, and must not have
/// been invalidated.
/// - The layout must be the same as used to allocate the handle.
/// - The same handle must not be resolved twice in a single call.
unsafe fn resolve_many_mut<const N: usize>(
&mut self,
handles: [(Self::Handle, Layout); N],
) -> [&mut Memory; N];
}
/// A storage that serves as a uniqueness barrier.
///
/// Notably, this means that this storage can go `&Storage -> &mut Memory`, and
/// thus it is possible to mutate the stored memory behind a shared storage
/// reference, and to mutably resolve multiple handles separately without
/// invalidating previously resolved handles.
///
/// [`resolve`]: Storage::resolve
/// [`resolve_mut`]: Storage::resolve_mut
pub unsafe trait SharedMutabilityStorage: Storage {
/// Resolve a memory handle in this storage to a mutable reference.
///
/// # Safety
///
/// - The handle must have been created by this storage, and must not have
/// been invalidated.
/// - The layout must be the same as used to allocate the handle.
unsafe fn resolve_raw(&self, handle: Self::Handle, layout: Layout) -> &mut Memory;
}
default unsafe impl<S> Storage for S
where
S: MultipleStorage,
{
default unsafe fn grow(
&mut self,
old_handle: Self::Handle,
old_layout: Layout,
new_layout: Layout,
) -> Result<Self::Handle, AllocError> {
debug_assert!(
new_layout.size() >= old_layout.size(),
"invalid arguments to Storage::grow",
);
let new_handle: Self::Handle = self.allocate(new_layout)?;
let [new_ptr, old_ptr] =
self.resolve_many_mut([(new_handle, new_layout), (old_handle, old_layout)]);
copy_nonoverlapping(
old_ptr.as_mut_ptr(),
new_ptr.as_mut_ptr(),
old_layout.size(),
);
self.deallocate(old_handle, old_layout);
Ok(new_handle)
}
default unsafe fn shrink(
&mut self,
old_handle: Self::Handle,
old_layout: Layout,
new_layout: Layout,
) -> Result<Self::Handle, AllocError> {
debug_assert!(
new_layout.size() <= old_layout.size(),
"invalid arguments to Storage::shrink",
);
let new_handle: Self::Handle = self.allocate(new_layout)?;
let [new_ptr, old_ptr] =
self.resolve_many_mut([(new_handle, new_layout), (old_handle, old_layout)]);
copy_nonoverlapping(
old_ptr.as_mut_ptr(),
new_ptr.as_mut_ptr(),
new_layout.size(),
);
self.deallocate(old_handle, old_layout);
Ok(new_handle)
}
}