Skip to main content

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}