use crate::{
bump::{Bump, BumpSlice, BumpView, Level},
unsync,
};
use allocator_api2::alloc::{AllocError, Allocator, Layout};
use core::{cell, ptr::NonNull};
unsafe impl<T> Allocator for Bump<T> {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
Allocator::allocate(&self.as_view(), layout)
}
unsafe fn deallocate(&self, _: NonNull<u8>, _: Layout) {}
unsafe fn shrink(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
unsafe { Allocator::shrink(&self.as_view(), ptr, old_layout, new_layout) }
}
}
unsafe impl Allocator for BumpSlice {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
Allocator::allocate(&self.as_view(), layout)
}
unsafe fn deallocate(&self, _: NonNull<u8>, _: Layout) {}
unsafe fn shrink(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
unsafe { Allocator::shrink(&self.as_view(), ptr, old_layout, new_layout) }
}
}
unsafe impl Allocator for BumpView<'_> {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
let len = layout.size();
match self.get_layout(layout) {
None => Err(AllocError),
Some(allocation) => Ok(NonNull::slice_from_raw_parts(allocation.ptr, len)),
}
}
unsafe fn deallocate(&self, _: NonNull<u8>, _: Layout) {}
unsafe fn shrink(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
unsafe { shrink_in_place(ptr, old_layout, new_layout) }
}
}
unsafe impl<T> Allocator for unsync::Bump<T> {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
<unsync::BumpSlice as Allocator>::allocate(self, layout)
}
unsafe fn deallocate(&self, _: NonNull<u8>, _: Layout) {}
unsafe fn shrink(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
unsafe { <unsync::BumpSlice as Allocator>::shrink(self, ptr, old_layout, new_layout) }
}
}
unsafe impl Allocator for unsync::BumpSlice {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
let len = layout.size();
match self.alloc(layout) {
None => Err(AllocError),
Some(allocation) => Ok(NonNull::slice_from_raw_parts(allocation, len)),
}
}
unsafe fn deallocate(&self, _: NonNull<u8>, _: Layout) {}
unsafe fn shrink(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
unsafe { shrink_in_place(ptr, old_layout, new_layout) }
}
}
unsafe fn shrink_in_place(
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
debug_assert!(new_layout.size() <= old_layout.size());
let len = new_layout.size();
let offset = ptr.align_offset(new_layout.align());
if offset > 0 {
if old_layout
.size()
.checked_sub(offset)
.is_none_or(|n| n < len)
{
return Err(AllocError);
}
let dst = unsafe { ptr.byte_add(offset) };
unsafe { ptr.copy_to(dst, len) };
dst
} else {
ptr
};
Ok(NonNull::slice_from_raw_parts(ptr, len))
}
pub struct WithAllocationInfo<A> {
allocation: cell::Cell<Level>,
observed_level: cell::Cell<Level>,
inner: A,
}
impl<'lt, A: ?Sized> WithAllocationInfo<&'lt A> {
pub fn new(arena: &'lt A) -> Self {
WithAllocationInfo {
allocation: cell::Cell::new(Level(0)),
observed_level: cell::Cell::new(Level(0)),
inner: arena,
}
}
}
impl<A> WithAllocationInfo<A> {
pub fn last_observed_level(&self) -> Level {
self.observed_level.get()
}
pub fn last_allocation_start(&self) -> Level {
self.allocation.get()
}
}
unsafe impl<T> Allocator for WithAllocationInfo<&'_ Bump<T>> {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
let len = layout.size();
match self.inner.as_view().try_alloc(layout) {
Ok(allocation) => {
self.allocation.set(Level(allocation.level.0 - len));
self.observed_level.set(allocation.level);
Ok(NonNull::slice_from_raw_parts(allocation.ptr, len))
}
Err(level) => {
self.observed_level.set(level);
Err(AllocError)
}
}
}
unsafe fn deallocate(&self, _: NonNull<u8>, _: Layout) {}
unsafe fn shrink(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
unsafe { Allocator::shrink(&self.inner, ptr, old_layout, new_layout) }
}
}
unsafe impl Allocator for WithAllocationInfo<&'_ BumpSlice> {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
let len = layout.size();
match self.inner.as_view().try_alloc(layout) {
Ok(allocation) => {
self.allocation.set(Level(allocation.level.0 - len));
self.observed_level.set(allocation.level);
Ok(NonNull::slice_from_raw_parts(allocation.ptr, len))
}
Err(level) => {
self.observed_level.set(level);
Err(AllocError)
}
}
}
unsafe fn deallocate(&self, _: NonNull<u8>, _: Layout) {}
unsafe fn shrink(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
unsafe { Allocator::shrink(&self.inner, ptr, old_layout, new_layout) }
}
}
unsafe impl Allocator for WithAllocationInfo<&'_ unsync::BumpSlice> {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
let len = layout.size();
match self.inner.try_alloc(layout) {
Ok(allocation) => {
self.allocation.set(Level(allocation.level.0 - len));
self.observed_level.set(allocation.level);
Ok(NonNull::slice_from_raw_parts(allocation.ptr, len))
}
Err(level) => {
self.observed_level.set(level);
Err(AllocError)
}
}
}
unsafe fn deallocate(&self, _: NonNull<u8>, _: Layout) {}
unsafe fn shrink(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
unsafe { Allocator::shrink(&self.inner, ptr, old_layout, new_layout) }
}
}