use std::{
alloc::Layout,
mem::MaybeUninit,
ops::{Bound, Range, RangeBounds},
};
fn range_bounds_to_range<R: RangeBounds<usize>>(range: R, len: usize) -> Range<usize> {
let start = match range.start_bound() {
Bound::Included(&n) => n,
Bound::Excluded(&n) => n.checked_add(1).expect("range start overflow"),
Bound::Unbounded => 0,
};
let end = match range.end_bound() {
Bound::Included(&n) => n.checked_add(1).expect("range end overflow"),
Bound::Excluded(&n) => n,
Bound::Unbounded => len,
};
assert!(start <= end, "range start ({start}) > end ({end})");
assert!(end <= len, "range end ({end}) > length ({len})");
start..end
}
#[derive(thiserror::Error, Debug)]
#[non_exhaustive]
pub enum Error {
#[error("exceeding the capacity maximum")]
CapacityOverflow,
#[error("can't grow {to_grow} elements, only available {available}")]
OverGrow {
to_grow: usize,
available: usize,
},
#[error("memory allocation of {layout:?} failed")]
AllocError {
layout: Layout,
#[doc(hidden)]
non_exhaustive: (),
},
#[error(transparent)]
System(#[from] std::io::Error),
}
pub type Result<T> = std::result::Result<T, Error>;
pub trait RawMem {
type Item;
fn allocated(&self) -> &[Self::Item];
fn allocated_mut(&mut self) -> &mut [Self::Item];
unsafe fn grow(
&mut self,
cap: usize,
fill: impl FnOnce(usize, (&mut [Self::Item], &mut [MaybeUninit<Self::Item>])),
) -> Result<&mut [Self::Item]>;
fn shrink(&mut self, cap: usize) -> Result<()>;
fn size_hint(&self) -> Option<usize> {
None
}
unsafe fn grow_assumed(&mut self, cap: usize) -> Result<&mut [Self::Item]> {
unsafe {
self.grow(cap, |inited, (_, uninit)| {
debug_assert_eq!(
inited,
uninit.len(),
"grown memory must be initialized, \
usually allocators-like provide uninitialized memory, \
which is only safe for writing"
)
})
}
}
unsafe fn grow_zeroed(&mut self, cap: usize) -> Result<&mut [Self::Item]> {
unsafe {
self.grow(cap, |_, (_, uninit)| {
uninit.as_mut_ptr().write_bytes(0u8, uninit.len());
})
}
}
unsafe fn grow_zeroed_exact(&mut self, cap: usize) -> Result<&mut [Self::Item]> {
unsafe {
self.grow(cap, |inited, (_, uninit)| {
uninit.get_unchecked_mut(inited..).as_mut_ptr().write_bytes(0u8, uninit.len());
})
}
}
fn grow_with(
&mut self,
addition: usize,
f: impl FnMut() -> Self::Item,
) -> Result<&mut [Self::Item]> {
unsafe {
self.grow(addition, |_, (_, uninit)| {
uninit::fill_with(uninit, f);
})
}
}
unsafe fn grow_with_exact(
&mut self,
addition: usize,
f: impl FnMut() -> Self::Item,
) -> Result<&mut [Self::Item]> {
unsafe {
self.grow(addition, |inited, (_, uninit)| {
uninit::fill_with(&mut uninit[inited..], f);
})
}
}
fn grow_filled(&mut self, cap: usize, value: Self::Item) -> Result<&mut [Self::Item]>
where
Self::Item: Clone,
{
unsafe {
self.grow(cap, |_, (_, uninit)| {
uninit::fill(uninit, value);
})
}
}
unsafe fn grow_filled_exact(
&mut self,
cap: usize,
value: Self::Item,
) -> Result<&mut [Self::Item]>
where
Self::Item: Clone,
{
unsafe {
self.grow(cap, |inited, (_, uninit)| {
uninit::fill(&mut uninit[inited..], value);
})
}
}
fn grow_within<R: RangeBounds<usize>>(&mut self, range: R) -> Result<&mut [Self::Item]>
where
Self::Item: Clone,
{
let Range { start, end } = range_bounds_to_range(range, self.allocated().len());
unsafe {
self.grow(end - start, |_, (within, uninit)| {
uninit::write_clone_of_slice(uninit, &within[start..end]);
})
}
}
fn grow_from_slice(&mut self, src: &[Self::Item]) -> Result<&mut [Self::Item]>
where
Self::Item: Clone,
{
unsafe {
self.grow(src.len(), |_, (_, uninit)| {
uninit::write_clone_of_slice(uninit, src);
})
}
}
}
pub trait FillFn<T> {
fn call(&mut self, inited: usize, slices: (&mut [T], &mut [MaybeUninit<T>]));
}
impl<T, F> FillFn<T> for F
where
F: FnMut(usize, (&mut [T], &mut [MaybeUninit<T>])),
{
fn call(&mut self, inited: usize, slices: (&mut [T], &mut [MaybeUninit<T>])) {
self(inited, slices)
}
}
struct CallOnce<F> {
inner: Option<F>,
}
impl<F> CallOnce<F> {
fn new(f: F) -> Self {
Self { inner: Some(f) }
}
}
impl<T, F> FillFn<T> for CallOnce<F>
where
F: FnOnce(usize, (&mut [T], &mut [MaybeUninit<T>])),
{
fn call(&mut self, inited: usize, slices: (&mut [T], &mut [MaybeUninit<T>])) {
let f = self.inner.take().expect("CallOnce::call called more than once");
f(inited, slices);
}
}
pub unsafe trait ErasedMem {
type Item;
fn erased_allocated(&self) -> &[Self::Item];
fn erased_allocated_mut(&mut self) -> &mut [Self::Item];
unsafe fn erased_grow(
&mut self,
cap: usize,
fill: &mut dyn FillFn<Self::Item>,
) -> Result<&mut [Self::Item]>;
fn erased_shrink(&mut self, cap: usize) -> Result<()>;
fn erased_size_hint(&self) -> Option<usize> {
None
}
}
macro_rules! impl_erased {
($ty:ty => $($imp:tt)+) => {
impl $($imp)+ {
type Item = $ty;
fn allocated(&self) -> &[Self::Item] {
(**self).erased_allocated()
}
fn allocated_mut(&mut self) -> &mut [Self::Item] {
(**self).erased_allocated_mut()
}
unsafe fn grow(
&mut self,
cap: usize,
fill: impl FnOnce(usize, (&mut [Self::Item], &mut [MaybeUninit<Self::Item>])),
) -> Result<&mut [Self::Item]> { unsafe {
(**self).erased_grow(cap, &mut CallOnce::new(fill))
}}
fn shrink(&mut self, cap: usize) -> Result<()> {
(**self).erased_shrink(cap)
}
fn size_hint(&self) -> Option<usize> {
(**self).erased_size_hint()
}
}
};
}
impl_erased!(All::Item => <'a, All: ?Sized + RawMem> RawMem for &'a mut All);
impl_erased!(I => <'a, I> RawMem for Box<dyn ErasedMem<Item = I> + 'a>);
impl_erased!(I => <'a, I> RawMem for Box<dyn ErasedMem<Item = I> + Sync + 'a>);
impl_erased!(I => <'a, I> RawMem for Box<dyn ErasedMem<Item = I> + Sync + Send + 'a>);
unsafe impl<All: RawMem + ?Sized> ErasedMem for All {
type Item = All::Item;
fn erased_allocated(&self) -> &[Self::Item] {
self.allocated()
}
fn erased_allocated_mut(&mut self) -> &mut [Self::Item] {
self.allocated_mut()
}
unsafe fn erased_grow(
&mut self,
cap: usize,
fill: &mut dyn FillFn<Self::Item>,
) -> Result<&mut [Self::Item]> {
unsafe { self.grow(cap, |inited, slices| fill.call(inited, slices)) }
}
fn erased_shrink(&mut self, cap: usize) -> Result<()> {
self.shrink(cap)
}
fn erased_size_hint(&self) -> Option<usize> {
self.size_hint()
}
}
pub mod uninit {
use std::{mem, mem::MaybeUninit, ptr, slice};
#[inline]
pub unsafe fn assume_init_mut<T>(s: &mut [MaybeUninit<T>]) -> &mut [T] {
unsafe { slice::from_raw_parts_mut(s.as_mut_ptr().cast::<T>(), s.len()) }
}
pub fn write_clone_of_slice<T: Clone>(uninit: &mut [MaybeUninit<T>], src: &[T]) {
assert_eq!(uninit.len(), src.len(), "slice lengths must match");
for (dst, val) in uninit.iter_mut().zip(src.iter()) {
dst.write(val.clone());
}
}
pub fn fill<T: Clone>(uninit: &mut [MaybeUninit<T>], val: T) {
let mut guard = Guard { slice: uninit, init: 0 };
if let Some((last, elems)) = guard.slice.split_last_mut() {
for el in elems.iter_mut() {
el.write(val.clone());
guard.init += 1;
}
last.write(val);
guard.init += 1;
}
mem::forget(guard);
}
pub fn fill_with<T>(uninit: &mut [MaybeUninit<T>], mut fill: impl FnMut() -> T) {
let mut guard = Guard { slice: uninit, init: 0 };
for el in guard.slice.iter_mut() {
el.write(fill());
guard.init += 1;
}
mem::forget(guard);
}
struct Guard<'a, T> {
slice: &'a mut [MaybeUninit<T>],
init: usize,
}
impl<T> Drop for Guard<'_, T> {
fn drop(&mut self) {
debug_assert!(self.init <= self.slice.len());
unsafe {
let inited_slice = self.slice.get_unchecked_mut(..self.init);
ptr::drop_in_place(assume_init_mut(inited_slice));
}
}
}
}