bump_scope/features/
bytemuck.rs

1use core::mem::MaybeUninit;
2
3use ::bytemuck::Zeroable;
4
5use crate::{
6    BaseAllocator, Bump, BumpBox, BumpScope, ErrorBehavior, MinimumAlignment, SupportedMinimumAlignment, alloc::AllocError,
7};
8
9#[cfg(feature = "panic-on-alloc")]
10use crate::panic_on_error;
11
12mod vec_ext;
13
14pub use vec_ext::VecExt;
15
16mod init_zeroed {
17    use super::*;
18
19    pub trait Sealed {}
20
21    impl<T: Zeroable> Sealed for BumpBox<'_, MaybeUninit<T>> {}
22    impl<T: Zeroable> Sealed for BumpBox<'_, [MaybeUninit<T>]> {}
23}
24
25/// Extension trait for [`BumpBox`] that adds the `init_zeroed` method.
26pub trait InitZeroed<'a>: init_zeroed::Sealed {
27    /// The initialized type.
28    type Output: ?Sized;
29
30    /// Initializes `self` by filling it with zero.
31    ///
32    /// # Examples
33    ///
34    /// ```
35    /// use bump_scope::{Bump, bytemuck::InitZeroed};
36    /// let bump: Bump = Bump::new();
37    ///
38    /// // single value
39    /// let uninit = bump.alloc_uninit::<i32>();
40    /// let init = uninit.init_zeroed();
41    /// assert_eq!(*init, 0);
42    ///
43    /// // slice
44    /// let uninit = bump.alloc_uninit_slice::<i32>(10);
45    /// let init = uninit.init_zeroed();
46    /// assert_eq!(*init, [0; 10]);
47    /// ```
48    #[must_use]
49    fn init_zeroed(self) -> BumpBox<'a, Self::Output>;
50}
51
52impl<'a, T: Zeroable> InitZeroed<'a> for BumpBox<'a, MaybeUninit<T>> {
53    type Output = T;
54
55    #[inline]
56    fn init_zeroed(mut self) -> BumpBox<'a, T> {
57        unsafe {
58            self.as_mut_ptr().write_bytes(0, 1);
59            self.assume_init()
60        }
61    }
62}
63
64impl<'a, T: Zeroable> InitZeroed<'a> for BumpBox<'a, [MaybeUninit<T>]> {
65    type Output = [T];
66
67    #[inline]
68    fn init_zeroed(mut self) -> BumpBox<'a, [T]> {
69        unsafe {
70            let len = self.len();
71            self.as_mut_ptr().write_bytes(0, len);
72            self.assume_init()
73        }
74    }
75}
76
77mod bump_ext {
78    use super::*;
79
80    pub trait Sealed {}
81
82    impl<A, const MIN_ALIGN: usize, const UP: bool, const GUARANTEED_ALLOCATED: bool, const DEALLOCATES: bool> Sealed
83        for Bump<A, MIN_ALIGN, UP, GUARANTEED_ALLOCATED, DEALLOCATES>
84    where
85        MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
86        A: BaseAllocator<GUARANTEED_ALLOCATED>,
87    {
88    }
89}
90
91mod bump_scope_ext {
92    use super::*;
93
94    pub trait Sealed {}
95
96    impl<A, const MIN_ALIGN: usize, const UP: bool, const GUARANTEED_ALLOCATED: bool, const DEALLOCATES: bool> Sealed
97        for BumpScope<'_, A, MIN_ALIGN, UP, GUARANTEED_ALLOCATED, DEALLOCATES>
98    where
99        MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
100        A: BaseAllocator<GUARANTEED_ALLOCATED>,
101    {
102    }
103}
104
105/// Extension trait for [`Bump`] that adds the `(try_)alloc_zeroed(_slice)` methods.
106pub trait BumpExt: bump_ext::Sealed {
107    /// Allocate a zeroed object.
108    ///
109    /// # Panics
110    /// Panics if the allocation fails.
111    ///
112    /// # Examples
113    /// ```
114    /// use bump_scope::{Bump, bytemuck::BumpExt};
115    /// let bump: Bump = Bump::new();
116    ///
117    /// let zero = bump.alloc_zeroed::<i32>();
118    /// assert_eq!(*zero, 0);
119    /// ```
120    #[cfg(feature = "panic-on-alloc")]
121    fn alloc_zeroed<T>(&self) -> BumpBox<'_, T>
122    where
123        T: Zeroable;
124
125    /// Allocate a zeroed object.
126    ///
127    /// # Errors
128    /// Errors if the allocation fails.
129    ///
130    /// # Examples
131    /// ```
132    /// use bump_scope::{Bump, bytemuck::BumpExt};
133    /// let bump: Bump = Bump::try_new()?;
134    ///
135    /// let zero = bump.try_alloc_zeroed::<i32>()?;
136    /// assert_eq!(*zero, 0);
137    /// # Ok::<(), bump_scope::alloc::AllocError>(())
138    /// ```
139    fn try_alloc_zeroed<T>(&self) -> Result<BumpBox<'_, T>, AllocError>
140    where
141        T: Zeroable;
142
143    /// Allocate a zeroed object slice.
144    ///
145    /// # Panics
146    /// Panics if the allocation fails.
147    ///
148    /// # Examples
149    /// ```
150    /// use bump_scope::{Bump, bytemuck::BumpExt};
151    /// let bump: Bump = Bump::new();
152    ///
153    /// let zeroes = bump.alloc_zeroed_slice::<i32>(3);
154    /// assert_eq!(*zeroes, [0; 3]);
155    /// ```
156    #[cfg(feature = "panic-on-alloc")]
157    fn alloc_zeroed_slice<T>(&self, len: usize) -> BumpBox<'_, [T]>
158    where
159        T: Zeroable;
160
161    /// Allocate a zeroed object slice.
162    ///
163    /// # Errors
164    /// Errors if the allocation fails.
165    ///
166    /// # Examples
167    /// ```
168    /// use bump_scope::{Bump, bytemuck::BumpExt};
169    /// let bump: Bump = Bump::try_new()?;
170    ///
171    /// let zeroes = bump.try_alloc_zeroed_slice::<i32>(3)?;
172    /// assert_eq!(*zeroes, [0; 3]);
173    /// # Ok::<(), bump_scope::alloc::AllocError>(())
174    /// ```
175    fn try_alloc_zeroed_slice<T>(&self, len: usize) -> Result<BumpBox<'_, [T]>, AllocError>
176    where
177        T: Zeroable;
178}
179
180/// Extension trait for [`BumpScope`] that adds the `(try_)alloc_zeroed(_slice)` methods.
181pub trait BumpScopeExt<'a>: bump_scope_ext::Sealed {
182    /// Allocate a zeroed object.
183    ///
184    /// # Panics
185    /// Panics if the allocation fails.
186    ///
187    /// # Examples
188    /// ```
189    /// use bump_scope::{Bump, bytemuck::BumpScopeExt};
190    /// let mut bump: Bump = Bump::new();
191    ///
192    /// bump.scoped(|bump| {
193    ///     let zero = bump.alloc_zeroed::<i32>();
194    ///     assert_eq!(*zero, 0);
195    /// });
196    /// ```
197    #[cfg(feature = "panic-on-alloc")]
198    fn alloc_zeroed<T>(&self) -> BumpBox<'a, T>
199    where
200        T: Zeroable;
201
202    /// Allocate a zeroed object.
203    ///
204    /// # Errors
205    /// Errors if the allocation fails.
206    ///
207    /// # Examples
208    /// ```
209    /// use bump_scope::{Bump, alloc::AllocError, bytemuck::BumpScopeExt};
210    /// let mut bump: Bump = Bump::try_new()?;
211    ///
212    /// bump.scoped(|bump| -> Result<(), AllocError> {
213    ///     let zero = bump.try_alloc_zeroed::<i32>()?;
214    ///     assert_eq!(*zero, 0);
215    ///     Ok(())
216    /// })?;
217    /// # Ok::<(), bump_scope::alloc::AllocError>(())
218    /// ```
219    fn try_alloc_zeroed<T>(&self) -> Result<BumpBox<'a, T>, AllocError>
220    where
221        T: Zeroable;
222
223    /// Allocate a zeroed object slice.
224    ///
225    /// # Panics
226    /// Panics if the allocation fails.
227    ///
228    /// # Examples
229    /// ```
230    /// use bump_scope::{Bump, bytemuck::BumpScopeExt};
231    /// let mut bump: Bump = Bump::new();
232    ///
233    /// bump.scoped(|bump| {
234    ///     let zeroes = bump.alloc_zeroed_slice::<i32>(3);
235    ///     assert_eq!(*zeroes, [0; 3]);
236    /// });
237    /// ```
238    #[cfg(feature = "panic-on-alloc")]
239    fn alloc_zeroed_slice<T>(&self, len: usize) -> BumpBox<'a, [T]>
240    where
241        T: Zeroable;
242
243    /// Allocate a zeroed object slice.
244    ///
245    /// # Errors
246    /// Errors if the allocation fails.
247    ///
248    /// # Examples
249    /// ```
250    /// use bump_scope::{Bump, alloc::AllocError, bytemuck::BumpScopeExt};
251    /// let mut bump: Bump = Bump::try_new()?;
252    ///
253    /// bump.scoped(|bump| -> Result<(), AllocError>  {
254    ///     let zeroes = bump.try_alloc_zeroed_slice::<i32>(3)?;
255    ///     assert_eq!(*zeroes, [0; 3]);
256    ///     Ok(())
257    /// })?;
258    /// # Ok::<(), bump_scope::alloc::AllocError>(())
259    /// ```
260    fn try_alloc_zeroed_slice<T>(&self, len: usize) -> Result<BumpBox<'a, [T]>, AllocError>
261    where
262        T: Zeroable;
263}
264
265impl<A, const MIN_ALIGN: usize, const UP: bool, const GUARANTEED_ALLOCATED: bool, const DEALLOCATES: bool> BumpExt
266    for Bump<A, MIN_ALIGN, UP, GUARANTEED_ALLOCATED, DEALLOCATES>
267where
268    MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
269    A: BaseAllocator<GUARANTEED_ALLOCATED>,
270{
271    #[inline(always)]
272    #[cfg(feature = "panic-on-alloc")]
273    fn alloc_zeroed<T>(&self) -> BumpBox<'_, T>
274    where
275        T: Zeroable,
276    {
277        self.as_scope().alloc_zeroed()
278    }
279
280    #[inline(always)]
281    fn try_alloc_zeroed<T>(&self) -> Result<BumpBox<'_, T>, AllocError>
282    where
283        T: Zeroable,
284    {
285        self.as_scope().try_alloc_zeroed()
286    }
287
288    #[inline(always)]
289    #[cfg(feature = "panic-on-alloc")]
290    fn alloc_zeroed_slice<T>(&self, len: usize) -> BumpBox<'_, [T]>
291    where
292        T: Zeroable,
293    {
294        self.as_scope().alloc_zeroed_slice(len)
295    }
296
297    #[inline(always)]
298    fn try_alloc_zeroed_slice<T>(&self, len: usize) -> Result<BumpBox<'_, [T]>, AllocError>
299    where
300        T: Zeroable,
301    {
302        self.as_scope().try_alloc_zeroed_slice(len)
303    }
304}
305
306impl<'a, A, const MIN_ALIGN: usize, const UP: bool, const GUARANTEED_ALLOCATED: bool, const DEALLOCATES: bool>
307    BumpScopeExt<'a> for BumpScope<'a, A, MIN_ALIGN, UP, GUARANTEED_ALLOCATED, DEALLOCATES>
308where
309    MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
310    A: BaseAllocator<GUARANTEED_ALLOCATED>,
311{
312    #[inline(always)]
313    #[cfg(feature = "panic-on-alloc")]
314    fn alloc_zeroed<T>(&self) -> BumpBox<'a, T>
315    where
316        T: Zeroable,
317    {
318        panic_on_error(self.generic_alloc_zeroed())
319    }
320
321    #[inline(always)]
322    fn try_alloc_zeroed<T>(&self) -> Result<BumpBox<'a, T>, AllocError>
323    where
324        T: Zeroable,
325    {
326        self.generic_alloc_zeroed()
327    }
328
329    #[inline(always)]
330    #[cfg(feature = "panic-on-alloc")]
331    fn alloc_zeroed_slice<T>(&self, len: usize) -> BumpBox<'a, [T]>
332    where
333        T: Zeroable,
334    {
335        panic_on_error(self.generic_alloc_zeroed_slice(len))
336    }
337
338    #[inline(always)]
339    fn try_alloc_zeroed_slice<T>(&self, len: usize) -> Result<BumpBox<'a, [T]>, AllocError>
340    where
341        T: Zeroable,
342    {
343        self.generic_alloc_zeroed_slice(len)
344    }
345}
346
347trait PrivateBumpScopeExt<'a> {
348    fn generic_alloc_zeroed<B: ErrorBehavior, T>(&self) -> Result<BumpBox<'a, T>, B>
349    where
350        T: Zeroable;
351
352    fn generic_alloc_zeroed_slice<B: ErrorBehavior, T>(&self, len: usize) -> Result<BumpBox<'a, [T]>, B>
353    where
354        T: Zeroable;
355}
356
357impl<'a, A, const MIN_ALIGN: usize, const UP: bool, const GUARANTEED_ALLOCATED: bool, const DEALLOCATES: bool>
358    PrivateBumpScopeExt<'a> for BumpScope<'a, A, MIN_ALIGN, UP, GUARANTEED_ALLOCATED, DEALLOCATES>
359where
360    MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
361    A: BaseAllocator<GUARANTEED_ALLOCATED>,
362{
363    #[inline(always)]
364    fn generic_alloc_zeroed<B: ErrorBehavior, T>(&self) -> Result<BumpBox<'a, T>, B>
365    where
366        T: Zeroable,
367    {
368        Ok(self.generic_alloc_uninit::<B, T>()?.init_zeroed())
369    }
370
371    #[inline(always)]
372    fn generic_alloc_zeroed_slice<B: ErrorBehavior, T>(&self, len: usize) -> Result<BumpBox<'a, [T]>, B>
373    where
374        T: Zeroable,
375    {
376        Ok(self.generic_alloc_uninit_slice::<B, T>(len)?.init_zeroed())
377    }
378}