use core::{fmt::Debug, num::NonZeroUsize, ptr::NonNull};
use crate::{
BaseAllocator, BumpScope,
chunk::ChunkHeader,
polyfill::transmute_mut,
raw_bump::{RawBump, RawChunk},
settings::{BumpAllocatorSettings, BumpSettings},
stats::AnyStats,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Checkpoint {
pub(crate) chunk: NonNull<ChunkHeader>,
pub(crate) address: NonZeroUsize,
}
impl Checkpoint {
pub(crate) fn new<A, S: BumpAllocatorSettings>(chunk: RawChunk<A, S>) -> Self {
let address = chunk.pos().addr();
let chunk = chunk.header.cast();
Checkpoint { chunk, address }
}
pub(crate) unsafe fn reset_within_chunk(self) {
unsafe {
let ptr = self.chunk.cast::<u8>().with_addr(self.address);
self.chunk.as_ref().pos.set(ptr);
}
}
}
#[must_use]
pub struct BumpScopeGuard<'a, A, S = BumpSettings>
where
A: BaseAllocator<S::GuaranteedAllocated>,
S: BumpAllocatorSettings,
{
bump: &'a mut RawBump<A, S>,
checkpoint: Checkpoint,
}
impl<A, S> Debug for BumpScopeGuard<'_, A, S>
where
A: BaseAllocator<S::GuaranteedAllocated>,
S: BumpAllocatorSettings,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
AnyStats::from(self.bump.stats()).debug_format("BumpScopeGuard", f)
}
}
impl<A, S> Drop for BumpScopeGuard<'_, A, S>
where
A: BaseAllocator<S::GuaranteedAllocated>,
S: BumpAllocatorSettings,
{
#[inline(always)]
fn drop(&mut self) {
self.reset();
}
}
impl<'a, A, S> BumpScopeGuard<'a, A, S>
where
A: BaseAllocator<S::GuaranteedAllocated>,
S: BumpAllocatorSettings,
{
#[inline(always)]
pub(crate) fn new(bump: &'a mut RawBump<A, S>) -> Self {
let checkpoint = bump.checkpoint();
Self { bump, checkpoint }
}
#[inline(always)]
pub fn scope(&mut self) -> &mut BumpScope<'_, A, S> {
unsafe { transmute_mut(self.bump) }
}
#[inline(always)]
pub fn reset(&mut self) {
unsafe { self.bump.reset_to(self.checkpoint) }
}
}