1use core::alloc::Layout;
4#[cfg(not(feature = "allocator-api2"))]
5use core::fmt;
6use core::marker::PhantomData;
7use core::ptr::{self, NonNull};
8#[cfg(feature = "zeroize")]
9use core::slice;
10
11#[cfg(all(feature = "alloc", not(feature = "allocator-api2")))]
12use core::mem::transmute;
13
14#[cfg(all(feature = "alloc", not(feature = "allocator-api2")))]
15use alloc_crate::alloc::{alloc as raw_alloc, dealloc as raw_dealloc};
16
17#[cfg(all(feature = "alloc", feature = "allocator-api2"))]
18pub use allocator_api2::alloc::Global;
19#[cfg(feature = "allocator-api2")]
20pub use allocator_api2::alloc::{AllocError, Allocator};
21
22#[cfg(feature = "zeroize")]
23use zeroize::Zeroize;
24
25#[cfg(all(not(test), feature = "alloc"))]
26pub use alloc_crate::alloc::handle_alloc_error;
27
28#[cfg(any(test, not(feature = "alloc")))]
29pub fn handle_alloc_error(layout: Layout) -> ! {
31 panic!("memory allocation of {} bytes failed", layout.size());
32}
33
34#[cfg(not(feature = "allocator-api2"))]
38#[derive(Copy, Clone, Debug, PartialEq, Eq)]
39pub struct AllocError;
40
41#[cfg(not(feature = "allocator-api2"))]
42impl fmt::Display for AllocError {
43 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44 f.write_str("memory allocation failed")
45 }
46}
47
48#[cfg(all(feature = "std", not(feature = "allocator-api2")))]
49impl std::error::Error for AllocError {}
50
51#[cfg(not(feature = "allocator-api2"))]
90pub unsafe trait Allocator {
91 fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>;
94
95 unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout);
102
103 #[inline]
106 fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
107 let ptr = self.allocate(layout)?;
108 unsafe { ptr::write_bytes(ptr.cast::<u8>().as_ptr(), 0, ptr.len()) };
110 Ok(ptr)
111 }
112
113 unsafe fn grow(
115 &self,
116 ptr: NonNull<u8>,
117 old_layout: Layout,
118 new_layout: Layout,
119 ) -> Result<NonNull<[u8]>, AllocError> {
120 debug_assert!(
121 new_layout.size() >= old_layout.size(),
122 "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
123 );
124
125 let new_ptr = self.allocate(new_layout)?;
129 let cp_len = old_layout.size().min(new_ptr.len());
130 if cp_len > 0 {
131 ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), cp_len);
132 }
133 self.deallocate(ptr, old_layout);
134 Ok(new_ptr)
135 }
136
137 unsafe fn grow_zeroed(
140 &self,
141 ptr: NonNull<u8>,
142 old_layout: Layout,
143 new_layout: Layout,
144 ) -> Result<NonNull<[u8]>, AllocError> {
145 debug_assert!(
146 new_layout.size() >= old_layout.size(),
147 "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
148 );
149
150 let new_ptr = self.allocate_zeroed(new_layout)?;
154 let cp_len = old_layout.size().min(new_ptr.len());
155 if cp_len > 0 {
156 ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), cp_len);
157 }
158 self.deallocate(ptr, old_layout);
159 Ok(new_ptr)
160 }
161
162 unsafe fn shrink(
164 &self,
165 ptr: NonNull<u8>,
166 old_layout: Layout,
167 new_layout: Layout,
168 ) -> Result<NonNull<[u8]>, AllocError> {
169 debug_assert!(
170 new_layout.size() <= old_layout.size(),
171 "`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
172 );
173
174 let new_ptr = self.allocate(new_layout)?;
178 let cp_len = old_layout.size().min(new_ptr.len());
179 if cp_len > 0 {
180 ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), cp_len);
181 }
182 self.deallocate(ptr, old_layout);
183 Ok(new_ptr)
184 }
185
186 #[inline(always)]
188 fn by_ref(&self) -> &Self
189 where
190 Self: Sized,
191 {
192 self
193 }
194}
195
196pub trait AllocateIn: Sized {
199 type Alloc: Allocator;
201
202 fn allocate_in(self, layout: Layout) -> Result<(NonNull<[u8]>, Self::Alloc), AllocError>;
205
206 #[inline]
210 fn allocate_zeroed_in(
211 self,
212 layout: Layout,
213 ) -> Result<(NonNull<[u8]>, Self::Alloc), AllocError> {
214 let (ptr, alloc) = self.allocate_in(layout)?;
215 unsafe { ptr::write_bytes(ptr.cast::<u8>().as_ptr(), 0, ptr.len()) };
217 Ok((ptr, alloc))
218 }
219}
220
221impl<A: Allocator> AllocateIn for A {
222 type Alloc = A;
223
224 #[inline]
225 fn allocate_in(self, layout: Layout) -> Result<(NonNull<[u8]>, Self::Alloc), AllocError> {
226 let data = self.allocate(layout)?;
227 Ok((data, self))
228 }
229
230 #[inline]
231 fn allocate_zeroed_in(
232 self,
233 layout: Layout,
234 ) -> Result<(NonNull<[u8]>, Self::Alloc), AllocError> {
235 let data = self.allocate_zeroed(layout)?;
236 Ok((data, self))
237 }
238}
239
240pub trait AllocatorDefault: Allocator + Clone + Default {
244 const DEFAULT: Self;
246}
247
248pub trait AllocatorZeroizes: Allocator {}
250
251pub trait SpillAlloc<'a>: Sized {
255 type NewIn<A: 'a>;
257
258 #[inline]
261 fn spill_alloc(self) -> Self::NewIn<Global> {
262 Self::spill_alloc_in(self, Global)
263 }
264
265 fn spill_alloc_in<A: Allocator + 'a>(self, alloc: A) -> Self::NewIn<A>;
268}
269
270#[cfg(any(not(feature = "alloc"), not(feature = "allocator-api2")))]
276#[derive(Debug, Clone, PartialEq, Eq)]
277#[cfg_attr(feature = "alloc", derive(Default, Copy))]
278pub struct Global;
279
280#[cfg(all(feature = "alloc", not(feature = "allocator-api2")))]
281unsafe impl Allocator for Global {
282 #[inline]
283 fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
284 let ptr = if layout.size() == 0 {
285 #[allow(clippy::useless_transmute)]
288 unsafe {
289 NonNull::new_unchecked(transmute(layout.align()))
290 }
291 } else {
292 let Some(ptr) = NonNull::new(unsafe { raw_alloc(layout) }) else {
293 return Err(AllocError);
294 };
295 ptr
296 };
297 Ok(NonNull::slice_from_raw_parts(ptr, layout.size()))
298 }
299
300 #[inline]
301 unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
302 if layout.size() > 0 {
303 raw_dealloc(ptr.as_ptr(), layout);
304 }
305 }
306}
307
308#[cfg(not(feature = "alloc"))]
309unsafe impl Allocator for Global {
313 fn allocate(&self, _layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
314 unimplemented!();
315 }
316
317 unsafe fn deallocate(&self, _ptr: NonNull<u8>, _layout: Layout) {
318 unimplemented!();
319 }
320}
321
322#[cfg(feature = "alloc")]
323impl AllocatorDefault for Global {
324 const DEFAULT: Self = Global;
325}
326
327#[derive(Debug, Default, PartialEq, Eq)]
329pub struct Fixed<'a>(PhantomData<&'a mut ()>);
330
331unsafe impl Allocator for Fixed<'_> {
332 #[inline(always)]
333 fn allocate(&self, _layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
334 Err(AllocError)
335 }
336
337 #[inline(always)]
338 unsafe fn grow(
339 &self,
340 ptr: NonNull<u8>,
341 old_layout: Layout,
342 new_layout: Layout,
343 ) -> Result<NonNull<[u8]>, AllocError> {
344 if old_layout.align() != new_layout.align() || new_layout.size() > old_layout.size() {
345 Err(AllocError)
346 } else {
347 Ok(NonNull::slice_from_raw_parts(ptr, old_layout.size()))
348 }
349 }
350
351 #[inline(always)]
352 unsafe fn shrink(
353 &self,
354 ptr: NonNull<u8>,
355 old_layout: Layout,
356 new_layout: Layout,
357 ) -> Result<NonNull<[u8]>, AllocError> {
358 if old_layout.align() != new_layout.align() || new_layout.size() > old_layout.size() {
359 Err(AllocError)
360 } else {
361 Ok(NonNull::slice_from_raw_parts(ptr, old_layout.size()))
362 }
363 }
364
365 #[inline]
366 unsafe fn deallocate(&self, _ptr: NonNull<u8>, _layout: Layout) {}
367}
368
369impl<'a> AllocatorDefault for Fixed<'a> {
370 const DEFAULT: Self = Self(PhantomData);
371}
372
373impl Clone for Fixed<'_> {
374 fn clone(&self) -> Self {
375 Fixed::DEFAULT
376 }
377}
378
379#[derive(Debug)]
382pub struct Spill<'a, A> {
383 alloc: A,
384 initial: *const u8,
385 _fixed: Fixed<'a>,
386}
387
388impl<'a, A> Spill<'a, A> {
389 pub(crate) const fn new(alloc: A, initial: *const u8, fixed: Fixed<'a>) -> Self {
390 Self {
391 alloc,
392 initial,
393 _fixed: fixed,
394 }
395 }
396}
397
398impl<A: Default + Allocator> Default for Spill<'_, A> {
399 #[inline]
400 fn default() -> Self {
401 Self::new(A::default(), ptr::null(), Fixed::DEFAULT)
402 }
403}
404
405unsafe impl<A: Allocator> Allocator for Spill<'_, A> {
406 #[inline]
407 fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
408 self.alloc.allocate(layout)
409 }
410
411 #[inline]
412 unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
413 if !ptr::eq(self.initial, ptr.as_ptr()) {
414 self.alloc.deallocate(ptr, layout)
415 }
416 }
417}
418
419impl<'a, A: Default + Allocator> Clone for Spill<'a, A> {
420 fn clone(&self) -> Self {
421 Self::default()
422 }
423}
424
425impl<'a, A: AllocatorDefault> AllocatorDefault for Spill<'a, A> {
426 const DEFAULT: Self = Self::new(A::DEFAULT, ptr::null(), Fixed::DEFAULT);
427}
428
429#[cfg(feature = "zeroize")]
430#[derive(Debug, Default, Clone, Copy)]
432pub struct ZeroizingAlloc<A>(pub A);
433
434#[cfg(feature = "zeroize")]
435unsafe impl<A: Allocator> Allocator for ZeroizingAlloc<A> {
436 #[inline]
437 fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
438 self.0.allocate(layout)
439 }
440
441 #[inline]
445 unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
446 if layout.size() > 0 {
447 let mem = slice::from_raw_parts_mut(ptr.as_ptr(), layout.size());
448 mem.zeroize();
449 }
450 self.0.deallocate(ptr, layout)
451 }
452}
453
454#[cfg(feature = "zeroize")]
455impl<A: AllocatorDefault> AllocatorDefault for ZeroizingAlloc<A> {
456 const DEFAULT: Self = ZeroizingAlloc(A::DEFAULT);
457}
458
459#[cfg(feature = "zeroize")]
460impl<'a, Z> SpillAlloc<'a> for &'a mut zeroize::Zeroizing<Z>
461where
462 Z: Zeroize + 'a,
463 &'a mut Z: SpillAlloc<'a>,
464{
465 type NewIn<A: 'a> = <&'a mut Z as SpillAlloc<'a>>::NewIn<ZeroizingAlloc<A>>;
466
467 #[inline]
468 fn spill_alloc_in<A: Allocator + 'a>(self, alloc: A) -> Self::NewIn<A> {
469 (&mut **self).spill_alloc_in(ZeroizingAlloc(alloc))
470 }
471}
472
473#[cfg(feature = "zeroize")]
474impl<A: Allocator> AllocatorZeroizes for ZeroizingAlloc<A> {}
475
476pub trait ConvertAlloc<Target> {
478 fn convert(self) -> Target;
480}