Skip to main content

bump_scope/
without_dealloc.rs

1use core::{alloc::Layout, ptr::NonNull};
2
3use crate::{
4    alloc::{AllocError, Allocator},
5    polyfill::non_null,
6    traits::BumpAllocatorCore,
7};
8
9/// Wraps a bump allocator and does nothing on [`deallocate`](Allocator::deallocate).
10///
11/// This type only implements [`Allocator`] for wrapped types that implement [`BumpAllocatorCore`], so you don't accidentally leak memory.
12///
13/// # Examples
14///
15/// ```
16/// # #[cfg(feature = "allocator-api2-04")]
17/// # {
18/// use bump_scope::{Bump, WithoutDealloc};
19/// use allocator_api2_04::boxed::Box;
20///
21/// let bump: Bump = Bump::new();
22///
23/// let boxed = Box::new_in(5, &bump);
24/// assert_eq!(bump.stats().allocated(), 4);
25/// drop(boxed);
26/// assert_eq!(bump.stats().allocated(), 0);
27///
28/// let boxed = Box::new_in(5, WithoutDealloc(&bump));
29/// assert_eq!(bump.stats().allocated(), 4);
30/// drop(boxed);
31/// assert_eq!(bump.stats().allocated(), 4);
32/// # }
33/// ```
34#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
35pub struct WithoutDealloc<A>(pub A);
36
37unsafe impl<A: BumpAllocatorCore> Allocator for WithoutDealloc<A> {
38    #[inline(always)]
39    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
40        self.0.allocate(layout)
41    }
42
43    #[inline(always)]
44    fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
45        self.0.allocate_zeroed(layout)
46    }
47
48    #[inline(always)]
49    unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
50        let _ = (ptr, layout);
51    }
52
53    #[inline(always)]
54    unsafe fn grow(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
55        unsafe { self.0.grow(ptr, old_layout, new_layout) }
56    }
57
58    #[inline(always)]
59    unsafe fn grow_zeroed(
60        &self,
61        ptr: NonNull<u8>,
62        old_layout: Layout,
63        new_layout: Layout,
64    ) -> Result<NonNull<[u8]>, AllocError> {
65        unsafe { self.0.grow_zeroed(ptr, old_layout, new_layout) }
66    }
67
68    #[inline(always)]
69    unsafe fn shrink(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
70        unsafe { self.0.shrink(ptr, old_layout, new_layout) }
71    }
72}
73
74/// Wraps a bump allocator and does nothing on [`shrink`](Allocator::shrink).
75///
76/// This type only implements [`Allocator`] for wrapped types that implement [`BumpAllocatorCore`], so you don't accidentally leak memory.
77#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
78pub struct WithoutShrink<A>(pub A);
79
80unsafe impl<A: BumpAllocatorCore> Allocator for WithoutShrink<A> {
81    #[inline(always)]
82    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
83        self.0.allocate(layout)
84    }
85
86    #[inline(always)]
87    fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
88        self.0.allocate_zeroed(layout)
89    }
90
91    #[inline(always)]
92    unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
93        unsafe { self.0.deallocate(ptr, layout) };
94    }
95
96    #[inline(always)]
97    unsafe fn grow(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
98        unsafe { self.0.grow(ptr, old_layout, new_layout) }
99    }
100
101    #[inline(always)]
102    unsafe fn grow_zeroed(
103        &self,
104        ptr: NonNull<u8>,
105        old_layout: Layout,
106        new_layout: Layout,
107    ) -> Result<NonNull<[u8]>, AllocError> {
108        unsafe { self.0.grow_zeroed(ptr, old_layout, new_layout) }
109    }
110
111    #[inline(always)]
112    unsafe fn shrink(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
113        #[cold]
114        #[inline(never)]
115        unsafe fn shrink_unfit<A: BumpAllocatorCore>(
116            this: &WithoutShrink<A>,
117            ptr: NonNull<u8>,
118            old_layout: Layout,
119            new_layout: Layout,
120        ) -> Result<NonNull<[u8]>, AllocError> {
121            let new_ptr = this.0.allocate(new_layout)?.cast::<u8>();
122            unsafe { ptr.copy_to_nonoverlapping(new_ptr, old_layout.size()) };
123            Ok(NonNull::slice_from_raw_parts(new_ptr, new_layout.size()))
124        }
125
126        unsafe {
127            if non_null::is_aligned_to(ptr, new_layout.align()) {
128                Ok(NonNull::slice_from_raw_parts(ptr, new_layout.size()))
129            } else {
130                // expected to virtually never occur
131                shrink_unfit(self, ptr, old_layout, new_layout)
132            }
133        }
134    }
135}