Skip to main content

bump_scope/traits/
bump_allocator_scope.rs

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