Skip to main content

bump_scope/traits/
bump_allocator.rs

1use core::ptr;
2
3use crate::{
4    BaseAllocator, Bump, BumpScope, BumpScopeGuard,
5    polyfill::transmute_mut,
6    settings::{BumpAllocatorSettings, MinimumAlignment, SupportedMinimumAlignment},
7    traits::MutBumpAllocatorTyped,
8};
9
10/// A bump allocator, generic over [`Bump`] and [`BumpScope`].
11///
12/// Many useful methods are only available for a [`BumpAllocatorScope`].
13/// You can access them by converting to a `BumpScope` using [`as_scope`] and [`as_mut_scope`].
14///
15/// [`BumpAllocatorScope`]: crate::traits::BumpAllocatorScope
16/// [`as_scope`]: BumpAllocator::as_scope
17/// [`as_mut_scope`]: BumpAllocator::as_mut_scope
18pub trait BumpAllocator: MutBumpAllocatorTyped + Sized {
19    /// The base allocator.
20    type Allocator: BaseAllocator<<Self::Settings as BumpAllocatorSettings>::GuaranteedAllocated>;
21
22    /// The bump allocator settings.
23    type Settings: BumpAllocatorSettings;
24
25    /// Returns this bump allocator as a `&BumpScope`.
26    #[must_use]
27    fn as_scope(&self) -> &BumpScope<'_, Self::Allocator, Self::Settings>;
28
29    /// Returns this bump allocator as a `&mut BumpScope`.
30    #[must_use]
31    fn as_mut_scope(&mut self) -> &mut BumpScope<'_, Self::Allocator, Self::Settings>;
32
33    /// Creates a new [`BumpScopeGuard`].
34    ///
35    /// This allows for creation of child scopes.
36    ///
37    /// # Panics
38    /// Panics if the bump allocator is currently [claimed].
39    ///
40    /// # Examples
41    ///
42    /// ```
43    /// # use bump_scope::Bump;
44    /// let mut bump: Bump = Bump::new();
45    ///
46    /// {
47    ///     let mut guard = bump.scope_guard();
48    ///     let bump = guard.scope();
49    ///     bump.alloc_str("Hello, world!");
50    ///     assert_eq!(bump.stats().allocated(), 13);
51    /// }
52    ///
53    /// assert_eq!(bump.stats().allocated(), 0);
54    /// ```
55    ///
56    /// [claimed]: crate::traits::BumpAllocatorScope::claim
57    #[inline(always)]
58    fn scope_guard(&mut self) -> BumpScopeGuard<'_, Self::Allocator, Self::Settings> {
59        BumpScopeGuard::new(&mut self.as_mut_scope().raw)
60    }
61
62    /// Calls `f` with a new child scope.
63    ///
64    /// # Panics
65    /// Panics if the bump allocator is currently [claimed].
66    ///
67    /// # Examples
68    /// ```
69    /// # use bump_scope::Bump;
70    /// let mut bump: Bump = Bump::new();
71    ///
72    /// bump.scoped(|bump| {
73    ///     bump.alloc_str("Hello, world!");
74    ///     assert_eq!(bump.stats().allocated(), 13);
75    /// });
76    ///
77    /// assert_eq!(bump.stats().allocated(), 0);
78    /// ```
79    ///
80    /// [claimed]: crate::traits::BumpAllocatorScope::claim
81    #[inline(always)]
82    fn scoped<R>(&mut self, f: impl FnOnce(&mut BumpScope<'_, Self::Allocator, Self::Settings>) -> R) -> R {
83        let mut guard = self.scope_guard();
84        f(guard.scope())
85    }
86
87    /// Calls `f` with a new child scope of a new minimum alignment.
88    ///
89    /// # Panics
90    /// Panics if the bump allocator is currently [claimed].
91    ///
92    /// # Examples
93    ///
94    #[cfg_attr(feature = "nightly-tests", doc = "```")]
95    #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
96    /// # #![feature(pointer_is_aligned_to)]
97    /// # use bump_scope::Bump;
98    /// let mut bump: Bump = Bump::with_size(512);
99    ///
100    /// // bump starts off by being aligned to 16
101    /// assert!(bump.stats().current_chunk().unwrap().bump_position().is_aligned_to(16));
102    ///
103    /// // allocate one byte
104    /// bump.alloc(1u8);
105    ///
106    /// // now the bump is only aligned to 1
107    /// // (if our `MIN_ALIGN` was higher, it would be that)
108    /// assert!(bump.stats().current_chunk().unwrap().bump_position().addr().get() % 2 == 1);
109    /// assert_eq!(bump.stats().allocated(), 1);
110    ///
111    /// bump.scoped_aligned::<8, ()>(|bump| {
112    ///    // in here, the bump will have the specified minimum alignment of 8
113    ///    assert!(bump.stats().current_chunk().unwrap().bump_position().is_aligned_to(8));
114    ///    assert_eq!(bump.stats().allocated(), 8);
115    ///
116    ///    // allocating a value with its size being a multiple of 8 will no longer have
117    ///    // to align the bump pointer before allocation
118    ///    bump.alloc(1u64);
119    ///    assert!(bump.stats().current_chunk().unwrap().bump_position().is_aligned_to(8));
120    ///    assert_eq!(bump.stats().allocated(), 16);
121    ///    
122    ///    // allocating a value smaller than the minimum alignment must align the bump pointer
123    ///    // after the allocation, resulting in some wasted space
124    ///    bump.alloc(1u8);
125    ///    assert!(bump.stats().current_chunk().unwrap().bump_position().is_aligned_to(8));
126    ///    assert_eq!(bump.stats().allocated(), 24);
127    /// });
128    ///
129    /// assert_eq!(bump.stats().allocated(), 1);
130    /// ```
131    ///
132    /// [claimed]: crate::traits::BumpAllocatorScope::claim
133    #[inline(always)]
134    fn scoped_aligned<const NEW_MIN_ALIGN: usize, R>(
135        &mut self,
136        f: impl FnOnce(
137            &mut BumpScope<Self::Allocator, <Self::Settings as BumpAllocatorSettings>::WithMinimumAlignment<NEW_MIN_ALIGN>>,
138        ) -> R,
139    ) -> R
140    where
141        MinimumAlignment<NEW_MIN_ALIGN>: SupportedMinimumAlignment,
142    {
143        // This guard will reset the bump pointer to the current position, which is aligned to `MIN_ALIGN`.
144        let mut guard = self.scope_guard();
145        let scope = guard.scope();
146        scope.raw.align::<NEW_MIN_ALIGN>();
147        f(unsafe { transmute_mut(scope) })
148    }
149}
150
151impl<A, S> BumpAllocator for Bump<A, S>
152where
153    A: BaseAllocator<S::GuaranteedAllocated>,
154    S: BumpAllocatorSettings,
155{
156    type Allocator = A;
157    type Settings = S;
158
159    #[inline(always)]
160    fn as_scope(&self) -> &BumpScope<'_, Self::Allocator, Self::Settings> {
161        // SAFETY: `Bump` and `BumpScope` both have the layout of `Cell<RawChunk>`
162        //         `BumpScope`'s api is a subset of `Bump`'s
163        unsafe { &*ptr::from_ref(self).cast() }
164    }
165
166    #[inline(always)]
167    fn as_mut_scope(&mut self) -> &mut BumpScope<'_, Self::Allocator, Self::Settings> {
168        // SAFETY: we shorten the lifetime that allocations will have which is sound
169        unsafe { transmute_mut(self) }
170    }
171}
172
173impl<A, S> BumpAllocator for BumpScope<'_, A, S>
174where
175    A: BaseAllocator<S::GuaranteedAllocated>,
176    S: BumpAllocatorSettings,
177{
178    type Allocator = A;
179    type Settings = S;
180
181    #[inline(always)]
182    fn as_scope(&self) -> &BumpScope<'_, Self::Allocator, Self::Settings> {
183        self
184    }
185
186    #[inline(always)]
187    fn as_mut_scope(&mut self) -> &mut BumpScope<'_, Self::Allocator, Self::Settings> {
188        // SAFETY: we shorten the lifetime that allocations will have which is sound
189        unsafe { transmute_mut(self) }
190    }
191}
192
193impl<B> BumpAllocator for &mut B
194where
195    B: BumpAllocator,
196{
197    type Allocator = B::Allocator;
198    type Settings = B::Settings;
199
200    fn as_scope(&self) -> &BumpScope<'_, Self::Allocator, Self::Settings> {
201        B::as_scope(self)
202    }
203
204    fn as_mut_scope(&mut self) -> &mut BumpScope<'_, Self::Allocator, Self::Settings> {
205        B::as_mut_scope(self)
206    }
207}