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