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