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 ≎ 1, 2, 3];
30 /// let vec2: BumpVec<u8, _> = bump_vec![in ≎ 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}