Skip to main content

bump_scope/traits/
bump_allocator.rs

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