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