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