1use crate::RawThinSlice;
2use bumpalo::Bump;
3use smallvec::SmallVec;
4
5#[expect(clippy::mut_from_ref)] pub trait BumpExt {
8 fn used_bytes(&self) -> usize;
10
11 fn alloc_as_slice<T>(&self, value: T) -> &mut [T];
13
14 fn alloc_from_iter<T>(&self, iter: impl Iterator<Item = T>) -> &mut [T];
18
19 fn alloc_vec<T>(&self, values: Vec<T>) -> &mut [T];
24
25 fn alloc_smallvec<A: smallvec::Array>(&self, values: SmallVec<A>) -> &mut [A::Item];
30
31 fn alloc_array<T, const N: usize>(&self, values: [T; N]) -> &mut [T];
36
37 unsafe fn alloc_slice_unchecked<'a, T>(&'a self, slice: &[T]) -> &'a mut [T];
45
46 fn alloc_as_thin_slice<H, T>(&self, header: H, value: T) -> &mut RawThinSlice<H, T>;
50
51 fn alloc_from_iter_thin<H, T>(
53 &self,
54 header: H,
55 iter: impl Iterator<Item = T>,
56 ) -> &mut RawThinSlice<H, T>;
57
58 fn alloc_vec_thin<H, T>(&self, header: H, values: Vec<T>) -> &mut RawThinSlice<H, T>;
60
61 fn alloc_smallvec_thin<H, A: smallvec::Array>(
63 &self,
64 header: H,
65 values: SmallVec<A>,
66 ) -> &mut RawThinSlice<H, A::Item>;
67
68 fn alloc_array_thin<H, T, const N: usize>(
70 &self,
71 header: H,
72 values: [T; N],
73 ) -> &mut RawThinSlice<H, T>;
74
75 fn alloc_thin_slice_copy<'a, H, T: Copy>(
77 &'a self,
78 header: H,
79 src: &[T],
80 ) -> &'a mut RawThinSlice<H, T> {
81 unsafe { self.alloc_thin_slice_unchecked(header, src) }
83 }
84
85 #[expect(clippy::missing_safety_doc)]
87 unsafe fn alloc_thin_slice_unchecked<'a, H, T>(
88 &'a self,
89 header: H,
90 src: &[T],
91 ) -> &'a mut RawThinSlice<H, T>;
92}
93
94impl BumpExt for Bump {
95 fn used_bytes(&self) -> usize {
96 unsafe { self.iter_allocated_chunks_raw().map(|(_ptr, len)| len).sum::<usize>() }
98 }
99
100 #[inline]
101 fn alloc_as_slice<T>(&self, value: T) -> &mut [T] {
102 std::slice::from_mut(self.alloc(value))
103 }
104
105 #[inline]
106 fn alloc_from_iter<T>(&self, mut iter: impl Iterator<Item = T>) -> &mut [T] {
107 match iter.size_hint() {
108 (min, Some(max)) if min == max => self.alloc_slice_fill_with(min, |_| {
109 iter.next().expect("Iterator supplied too few elements")
110 }),
111 _ => self.alloc_smallvec(SmallVec::<[T; 8]>::from_iter(iter)),
112 }
113 }
114
115 #[inline]
116 fn alloc_vec<T>(&self, mut values: Vec<T>) -> &mut [T] {
117 if values.is_empty() {
118 return &mut [];
119 }
120
121 unsafe {
123 let r = self.alloc_slice_unchecked(values.as_slice());
124 values.set_len(0);
125 r
126 }
127 }
128
129 #[inline]
130 fn alloc_smallvec<A: smallvec::Array>(&self, mut values: SmallVec<A>) -> &mut [A::Item] {
131 if values.is_empty() {
132 return &mut [];
133 }
134
135 unsafe {
137 let r = self.alloc_slice_unchecked(values.as_slice());
138 values.set_len(0);
139 r
140 }
141 }
142
143 #[inline]
144 fn alloc_array<T, const N: usize>(&self, values: [T; N]) -> &mut [T] {
145 if values.is_empty() {
146 return &mut [];
147 }
148
149 let values = std::mem::ManuallyDrop::new(values);
150 unsafe { self.alloc_slice_unchecked(values.as_slice()) }
152 }
153
154 #[inline]
155 unsafe fn alloc_slice_unchecked<'a, T>(&'a self, src: &[T]) -> &'a mut [T] {
156 let layout = std::alloc::Layout::for_value(src);
158 let dst = self.alloc_layout(layout).cast::<T>();
159 unsafe {
160 std::ptr::copy_nonoverlapping(src.as_ptr(), dst.as_ptr(), src.len());
161 std::slice::from_raw_parts_mut(dst.as_ptr(), src.len())
162 }
163 }
164
165 #[inline]
166 fn alloc_as_thin_slice<H, T>(&self, header: H, value: T) -> &mut RawThinSlice<H, T> {
167 let value = std::mem::ManuallyDrop::new(value);
168 unsafe { self.alloc_thin_slice_unchecked(header, std::slice::from_ref(&*value)) }
169 }
170
171 #[inline]
172 fn alloc_from_iter_thin<H, T>(
173 &self,
174 header: H,
175 mut iter: impl Iterator<Item = T>,
176 ) -> &mut RawThinSlice<H, T> {
177 match iter.size_hint() {
178 (min, Some(max)) if min == max => {
179 RawThinSlice::<H, T>::from_arena_with(self, header, min, |_| {
180 iter.next().expect("Iterator supplied too few elements")
181 })
182 }
183 _ => self.alloc_smallvec_thin(header, SmallVec::<[T; 8]>::from_iter(iter)),
184 }
185 }
186
187 #[inline]
188 fn alloc_vec_thin<H, T>(&self, header: H, mut values: Vec<T>) -> &mut RawThinSlice<H, T> {
189 unsafe {
191 let r = self.alloc_thin_slice_unchecked(header, values.as_slice());
192 values.set_len(0);
193 r
194 }
195 }
196
197 #[inline]
198 fn alloc_smallvec_thin<H, A: smallvec::Array>(
199 &self,
200 header: H,
201 mut values: SmallVec<A>,
202 ) -> &mut RawThinSlice<H, A::Item> {
203 unsafe {
205 let r = self.alloc_thin_slice_unchecked(header, values.as_slice());
206 values.set_len(0);
207 r
208 }
209 }
210
211 #[inline]
212 fn alloc_array_thin<H, T, const N: usize>(
213 &self,
214 header: H,
215 values: [T; N],
216 ) -> &mut RawThinSlice<H, T> {
217 let values = std::mem::ManuallyDrop::new(values);
218 unsafe { self.alloc_thin_slice_unchecked(header, values.as_slice()) }
220 }
221
222 #[inline]
223 unsafe fn alloc_thin_slice_unchecked<'a, H, T>(
224 &'a self,
225 header: H,
226 src: &[T],
227 ) -> &'a mut RawThinSlice<H, T> {
228 RawThinSlice::from_arena(self, header, src)
229 }
230}
231
232#[cfg(test)]
233mod tests {
234 use super::*;
235
236 #[derive(Debug, PartialEq, Eq)]
237 struct DropBomb(i32, bool);
238 impl DropBomb {
239 fn new(i: i32) -> Self {
240 Self(i, true)
241 }
242 fn defuse(&mut self) {
243 self.1 = false;
244 }
245 }
246 impl Drop for DropBomb {
247 fn drop(&mut self) {
248 if self.1 && !std::thread::panicking() {
249 panic!("boom");
250 }
251 }
252 }
253
254 #[test]
255 fn test_alloc_vec() {
256 let bump = Bump::new();
257 let vec = vec![DropBomb::new(1), DropBomb::new(2), DropBomb::new(3)];
258 let other_vec = vec![DropBomb::new(1), DropBomb::new(2), DropBomb::new(3)];
259 let slice = bump.alloc_vec(vec);
260 assert_eq!(slice, &other_vec[..]);
261 for item in slice {
262 item.defuse();
263 }
264 for mut item in other_vec {
265 item.defuse();
266 }
267 }
268
269 #[test]
270 fn test_alloc_vec_thin() {
271 let bump = Bump::new();
272 let vec = vec![DropBomb::new(1), DropBomb::new(2), DropBomb::new(3)];
273 let other_vec = vec![DropBomb::new(1), DropBomb::new(2), DropBomb::new(3)];
274 let raw_slice = bump.alloc_vec_thin(69usize, vec);
275 assert_eq!(*raw_slice.header(), 69usize);
276 let slice = &mut **raw_slice;
277 assert_eq!(slice, &other_vec[..]);
278 for item in slice {
279 item.defuse();
280 }
281 for mut item in other_vec {
282 item.defuse();
283 }
284 }
285
286 #[test]
287 fn test_alloc_thin_empty() {
288 let bump = Bump::new();
289 let data = Vec::<&'static str>::new();
290 let raw_slice = bump.alloc_vec_thin(69usize, data);
291 assert_eq!(*raw_slice.header(), 69usize);
292 assert!(raw_slice.as_slice().is_empty());
293 }
294}