bump_scope/
bump_scope_guard.rs

1use core::{fmt::Debug, marker::PhantomData, num::NonZeroUsize, ptr::NonNull};
2
3use crate::{
4    Bump, BumpScope, MinimumAlignment, RawChunk, SupportedMinimumAlignment,
5    alloc::Allocator,
6    chunk_header::ChunkHeader,
7    stats::{AnyStats, Stats},
8};
9
10/// This is returned from [`checkpoint`](Bump::checkpoint) and used for [`reset_to`](Bump::reset_to).
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
12pub struct Checkpoint {
13    pub(crate) chunk: NonNull<ChunkHeader>,
14    pub(crate) address: NonZeroUsize,
15}
16
17impl Checkpoint {
18    pub(crate) fn new<A, const UP: bool, const GUARANTEED_ALLOCATED: bool>(
19        chunk: RawChunk<A, UP, GUARANTEED_ALLOCATED>,
20    ) -> Self {
21        let address = chunk.pos().addr();
22        let chunk = chunk.header().cast();
23        Checkpoint { chunk, address }
24    }
25
26    pub(crate) unsafe fn reset_within_chunk(self) {
27        unsafe {
28            let ptr = self.chunk.cast::<u8>().with_addr(self.address);
29            self.chunk.as_ref().pos.set(ptr);
30        }
31    }
32}
33
34/// Returned from [`BumpScope::scope_guard`].
35pub struct BumpScopeGuard<'a, A, const MIN_ALIGN: usize = 1, const UP: bool = true, const DEALLOCATES: bool = true>
36where
37    MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
38{
39    pub(crate) chunk: RawChunk<A, UP, true>,
40    address: usize,
41    marker: PhantomData<&'a mut ()>,
42}
43
44impl<A, const MIN_ALIGN: usize, const UP: bool, const DEALLOCATES: bool> Debug
45    for BumpScopeGuard<'_, A, MIN_ALIGN, UP, DEALLOCATES>
46where
47    MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
48{
49    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
50        AnyStats::from(self.stats()).debug_format("BumpScopeGuard", f)
51    }
52}
53
54impl<A, const MIN_ALIGN: usize, const UP: bool, const DEALLOCATES: bool> Drop
55    for BumpScopeGuard<'_, A, MIN_ALIGN, UP, DEALLOCATES>
56where
57    MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
58{
59    #[inline(always)]
60    fn drop(&mut self) {
61        self.reset();
62    }
63}
64
65impl<'a, A, const MIN_ALIGN: usize, const UP: bool, const DEALLOCATES: bool>
66    BumpScopeGuard<'a, A, MIN_ALIGN, UP, DEALLOCATES>
67where
68    MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
69{
70    #[inline(always)]
71    pub(crate) fn new(bump: &'a mut BumpScope<'_, A, MIN_ALIGN, UP, true, DEALLOCATES>) -> Self {
72        unsafe { Self::new_unchecked(bump.chunk.get()) }
73    }
74
75    #[inline(always)]
76    pub(crate) unsafe fn new_unchecked(chunk: RawChunk<A, UP, true>) -> Self {
77        Self {
78            chunk,
79            address: chunk.pos().addr().get(),
80            marker: PhantomData,
81        }
82    }
83
84    /// Returns a new `BumpScope`.
85    #[inline(always)]
86    pub fn scope(&mut self) -> BumpScope<'_, A, MIN_ALIGN, UP, true, DEALLOCATES> {
87        unsafe { BumpScope::new_unchecked(self.chunk) }
88    }
89
90    /// Frees the memory taken up by allocations made since creation of this bump scope guard.
91    #[inline(always)]
92    pub fn reset(&mut self) {
93        unsafe {
94            self.chunk.set_pos_addr(self.address);
95        }
96    }
97
98    /// Returns a type which provides statistics about the memory usage of the bump allocator.
99    #[must_use]
100    #[inline(always)]
101    pub fn stats(&self) -> Stats<'a, A, UP> {
102        self.chunk.stats()
103    }
104
105    /// Returns a reference to the base allocator.
106    #[must_use]
107    #[inline(always)]
108    pub fn allocator(&self) -> &'a A {
109        self.stats().current_chunk().allocator()
110    }
111}
112
113/// Returned from [`Bump::scope_guard`].
114///
115/// This fulfills the same purpose as [`BumpScopeGuard`], but it does not need to store
116/// the address which the bump pointer needs to be reset to. It simply resets the bump pointer to the very start.
117///
118/// It is allowed to do so because it takes a `&mut Bump` to create this guard. This means that no
119/// allocations can be live when the guard is created.
120pub struct BumpScopeGuardRoot<'b, A, const MIN_ALIGN: usize = 1, const UP: bool = true, const DEALLOCATES: bool = true>
121where
122    MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
123    A: Allocator,
124{
125    pub(crate) chunk: RawChunk<A, UP, true>,
126    marker: PhantomData<&'b mut ()>,
127}
128
129impl<A, const MIN_ALIGN: usize, const UP: bool, const DEALLOCATES: bool> Debug
130    for BumpScopeGuardRoot<'_, A, MIN_ALIGN, UP, DEALLOCATES>
131where
132    MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
133    A: Allocator,
134{
135    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
136        AnyStats::from(self.stats()).debug_format("BumpScopeGuardRoot", f)
137    }
138}
139
140impl<A, const MIN_ALIGN: usize, const UP: bool, const DEALLOCATES: bool> Drop
141    for BumpScopeGuardRoot<'_, A, MIN_ALIGN, UP, DEALLOCATES>
142where
143    MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
144    A: Allocator,
145{
146    #[inline(always)]
147    fn drop(&mut self) {
148        self.reset();
149    }
150}
151
152impl<'a, A, const MIN_ALIGN: usize, const UP: bool, const DEALLOCATES: bool>
153    BumpScopeGuardRoot<'a, A, MIN_ALIGN, UP, DEALLOCATES>
154where
155    MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
156    A: Allocator,
157{
158    #[inline(always)]
159    pub(crate) fn new(bump: &'a mut Bump<A, MIN_ALIGN, UP, true, DEALLOCATES>) -> Self {
160        unsafe { Self::new_unchecked(bump.chunk.get()) }
161    }
162
163    #[inline(always)]
164    pub(crate) unsafe fn new_unchecked(chunk: RawChunk<A, UP, true>) -> Self {
165        Self {
166            chunk,
167            marker: PhantomData,
168        }
169    }
170
171    /// Returns a new `BumpScope`.
172    #[inline(always)]
173    pub fn scope(&mut self) -> BumpScope<'_, A, MIN_ALIGN, UP, true, DEALLOCATES> {
174        unsafe { BumpScope::new_unchecked(self.chunk) }
175    }
176
177    /// Frees the memory taken up by allocations made since creation of this bump scope guard.
178    #[inline(always)]
179    pub fn reset(&mut self) {
180        self.chunk.reset();
181    }
182
183    /// Returns a type which provides statistics about the memory usage of the bump allocator.
184    #[must_use]
185    #[inline(always)]
186    pub fn stats(&self) -> Stats<'a, A, UP> {
187        self.chunk.stats()
188    }
189
190    /// Returns a reference to the base allocator.
191    #[must_use]
192    #[inline(always)]
193    pub fn allocator(&self) -> &'a A {
194        self.stats().current_chunk().allocator()
195    }
196}