Skip to main content

bump_scope/traits/
bump_allocator_scope.rs

1use crate::{
2    BumpClaimGuard, BumpScope,
3    alloc::Allocator,
4    bump_align_guard::BumpAlignGuard,
5    polyfill::transmute_mut,
6    settings::{BumpAllocatorSettings, MinimumAlignment, SupportedMinimumAlignment},
7    stats::Stats,
8    traits::{BumpAllocator, MutBumpAllocatorCoreScope},
9};
10
11/// A bump allocator scope.
12pub trait BumpAllocatorScope<'a>: BumpAllocator + MutBumpAllocatorCoreScope<'a> {
13    /// Claims exclusive access to the bump allocator from a shared reference.
14    ///
15    /// This makes it possible to enter scopes while a there are still outstanding
16    /// references to that bump allocator.
17    ///
18    /// The current reference to the bump allocator will be marked as claimed which
19    /// makes any allocation api fail, causes the scope api to panic and makes `stats`
20    /// return an object that reports that no chunks are allocated.
21    ///
22    /// # Panics
23    /// Panics if the bump allocator is already claimed.
24    ///
25    /// # Examples
26    /// ```
27    /// use bump_scope::{Bump, BumpVec, bump_vec};
28    ///
29    /// let bump: Bump = Bump::new();
30    /// let vec1: BumpVec<u8, _> = bump_vec![in &bump; 1, 2, 3];
31    /// let vec2: BumpVec<u8, _> = bump_vec![in &bump; 4, 5, 6];
32    ///
33    /// bump.claim().scoped(|bump| {
34    ///     // ...
35    ///     # _ = bump;
36    /// });
37    ///
38    /// assert_eq!(vec1, [1, 2, 3]);
39    /// assert_eq!(vec2, [4, 5, 6]);
40    /// ```
41    fn claim(&self) -> BumpClaimGuard<'_, 'a, Self::Allocator, Self::Settings>;
42
43    /// Returns a type which provides statistics about the memory usage of the bump allocator.
44    fn stats(&self) -> Stats<'a, Self::Settings>;
45
46    /// Calls `f` with this scope but with a new minimum alignment.
47    ///
48    /// # Examples
49    ///
50    /// Increase the minimum alignment:
51    #[cfg_attr(feature = "nightly-tests", doc = "```")]
52    #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
53    /// # #![feature(pointer_is_aligned_to)]
54    /// # use bump_scope::Bump;
55    /// let mut bump: Bump = Bump::new();
56    /// let bump = bump.as_mut_scope();
57    ///
58    /// // here we're allocating with a `MIN_ALIGN` of `1`
59    /// let foo = bump.alloc_str("foo");
60    /// assert_eq!(bump.stats().allocated(), 3);
61    ///
62    /// let bar = bump.aligned::<8, _>(|bump| {
63    ///     // in here the bump position has been aligned to `8`
64    ///     assert_eq!(bump.stats().allocated(), 8);
65    ///     assert!(bump.stats().current_chunk().unwrap().bump_position().is_aligned_to(8));
66    ///
67    ///     // make some allocations that benefit from the higher `MIN_ALIGN` of `8`
68    ///     let bar = bump.alloc(0u64);
69    ///     assert_eq!(bump.stats().allocated(), 16);
70    ///  
71    ///     // the bump position will stay aligned to `8`
72    ///     bump.alloc(0u8);
73    ///     assert_eq!(bump.stats().allocated(), 24);
74    ///
75    ///     bar
76    /// });
77    ///
78    /// assert_eq!(bump.stats().allocated(), 24);
79    ///
80    /// // continue making allocations with a `MIN_ALIGN` of `1`
81    /// let baz = bump.alloc_str("baz");
82    /// assert_eq!(bump.stats().allocated(), 24 + 3);
83    ///
84    /// dbg!(foo, bar, baz);
85    /// ```
86    ///
87    /// Decrease the minimum alignment:
88    #[cfg_attr(feature = "nightly-tests", doc = "```")]
89    #[cfg_attr(not(feature = "nightly-tests"), doc = "```ignore")]
90    /// # #![feature(pointer_is_aligned_to)]
91    /// # use bump_scope::{Bump, alloc::Global, settings::{BumpSettings, BumpAllocatorSettings}};
92    /// type Settings = <BumpSettings as BumpAllocatorSettings>::WithMinimumAlignment<8>;
93    ///
94    /// let mut bump: Bump<Global, Settings> = Bump::new();
95    /// let bump = bump.as_mut_scope();
96    ///
97    /// // make some allocations that benefit from the `MIN_ALIGN` of `8`
98    /// let foo = bump.alloc(0u64);
99    ///
100    /// let bar = bump.aligned::<1, _>(|bump| {
101    ///     // make some allocations that benefit from the lower `MIN_ALIGN` of `1`
102    ///     let bar = bump.alloc(0u8);
103    ///
104    ///     // the bump position will not get aligned to `8` in here
105    ///     assert_eq!(bump.stats().allocated(), 8 + 1);
106    ///
107    ///     bar
108    /// });
109    ///
110    /// // after `aligned()`, the bump position will be aligned to `8` again
111    /// // to satisfy our `MIN_ALIGN`
112    /// assert!(bump.stats().current_chunk().unwrap().bump_position().is_aligned_to(8));
113    /// assert_eq!(bump.stats().allocated(), 16);
114    ///
115    /// // continue making allocations that benefit from the `MIN_ALIGN` of `8`
116    /// let baz = bump.alloc(0u64);
117    ///
118    /// dbg!(foo, bar, baz);
119    /// ```
120    fn aligned<const NEW_MIN_ALIGN: usize, R>(
121        &mut self,
122        f: impl FnOnce(
123            &mut BumpScope<
124                'a,
125                Self::Allocator,
126                <Self::Settings as BumpAllocatorSettings>::WithMinimumAlignment<NEW_MIN_ALIGN>,
127            >,
128        ) -> R,
129    ) -> R
130    where
131        MinimumAlignment<NEW_MIN_ALIGN>: SupportedMinimumAlignment;
132
133    /// Returns a reference to the base allocator.
134    #[must_use]
135    fn allocator(&self) -> &Self::Allocator;
136}
137
138impl<'a, B> BumpAllocatorScope<'a> for &mut B
139where
140    B: BumpAllocatorScope<'a>,
141{
142    #[inline(always)]
143    fn claim(&self) -> BumpClaimGuard<'_, 'a, Self::Allocator, Self::Settings> {
144        B::claim(self)
145    }
146
147    #[inline(always)]
148    fn stats(&self) -> Stats<'a, Self::Settings> {
149        B::stats(self)
150    }
151
152    #[inline(always)]
153    fn aligned<const NEW_MIN_ALIGN: usize, R>(
154        &mut self,
155        f: impl FnOnce(
156            &mut BumpScope<
157                'a,
158                Self::Allocator,
159                <Self::Settings as BumpAllocatorSettings>::WithMinimumAlignment<NEW_MIN_ALIGN>,
160            >,
161        ) -> R,
162    ) -> R
163    where
164        MinimumAlignment<NEW_MIN_ALIGN>: SupportedMinimumAlignment,
165    {
166        B::aligned::<NEW_MIN_ALIGN, R>(self, f)
167    }
168
169    #[inline(always)]
170    fn allocator(&self) -> &Self::Allocator {
171        B::allocator(self)
172    }
173}
174
175impl<'a, A, S> BumpAllocatorScope<'a> for BumpScope<'a, A, S>
176where
177    A: Allocator,
178    S: BumpAllocatorSettings,
179{
180    #[inline]
181    fn claim(&self) -> BumpClaimGuard<'_, 'a, Self::Allocator, Self::Settings> {
182        BumpClaimGuard::new(self)
183    }
184
185    #[inline]
186    fn stats(&self) -> Stats<'a, Self::Settings> {
187        BumpScope::stats(self)
188    }
189
190    #[inline]
191    fn aligned<const NEW_MIN_ALIGN: usize, R>(
192        &mut self,
193        f: impl FnOnce(
194            &mut BumpScope<
195                'a,
196                Self::Allocator,
197                <Self::Settings as BumpAllocatorSettings>::WithMinimumAlignment<NEW_MIN_ALIGN>,
198            >,
199        ) -> R,
200    ) -> R
201    where
202        MinimumAlignment<NEW_MIN_ALIGN>: SupportedMinimumAlignment,
203    {
204        if NEW_MIN_ALIGN < S::MIN_ALIGN {
205            let guard = BumpAlignGuard::new(self);
206
207            // SAFETY: bump is already aligned to `NEW_MIN_ALIGN` and the guard will ensure
208            // that the bump pointer will again be aligned to `MIN_ALIGN` once it drops
209            let bump = unsafe { transmute_mut(guard.scope) };
210
211            f(bump)
212        } else {
213            self.align::<NEW_MIN_ALIGN>();
214
215            // SAFETY: we aligned the bump pointer
216            let bump = unsafe { transmute_mut(self) };
217
218            f(bump)
219        }
220    }
221
222    #[inline(always)]
223    fn allocator(&self) -> &Self::Allocator {
224        &self.raw.allocator
225    }
226}