noop_allocator/
lib.rs

1#![no_std]
2#![feature(allocator_api)]
3#![feature(alloc_layout_extra)]
4#![warn(rust_2018_idioms)]
5
6#[cfg(feature = "alloc")]
7extern crate alloc;
8use core::{
9    alloc::{AllocError, Allocator, Layout},
10    marker::PhantomData,
11    ptr::NonNull,
12};
13
14/// An [`Allocator`] that does nothing.
15///
16/// Specifically:
17/// * [`allocate`][NoopAllocator::allocate] and
18///   [`allocate_zeroed`][NoopAllocator::allocate_zeroed] will return `Err` for
19///   any non-zero-sized allocation requests
20/// * [`deallocate`][NoopAllocator::deallocate] is a no-op, and does not require
21///   that `ptr` be "currently allocated", or fit `layout`.
22/// * [`shrink`][NoopAllocator::shrink], [`grow`][NoopAllocator::grow], and
23///   [`grow_zeroed`][NoopAllocator::grow_zeroed] do not require that `ptr` be
24///   "currently allocated", or fit `old_layout`, and will successfully return
25///   the original pointer unchanged (with the length of the new layout) if the
26///   `ptr` is aligned for the new layout and the new layout is smaller or the
27///   same size as the old layout.
28///
29/// This type is usable as an [`Allocator`] when you want to borrow an existing
30/// memory range for use in a single-allocation collection type, for example in
31/// [`Box`][alloc::boxed::Box] or [`Vec`][alloc::vec::Vec].
32///
33/// # Safety:
34///
35/// Many functions in this crate assume that `impl Allocator for
36/// NoopAllocator<'_>` as described above is sound, but `feature(allocator_api)`
37/// is unstable and the preconditions may change.
38#[repr(transparent)]
39pub struct NoopAllocator<'a>(PhantomData<&'a ()>);
40
41impl<'a> NoopAllocator<'a> {
42    /// Creates a new `NoopAllocator<'a>`.
43    pub const fn new() -> Self {
44        Self(PhantomData)
45    }
46}
47
48impl<'a> Default for NoopAllocator<'a> {
49    fn default() -> Self {
50        Self::new()
51    }
52}
53
54unsafe impl Allocator for NoopAllocator<'_> {
55    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
56        if layout.size() == 0 {
57            Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0))
58        } else {
59            Err(AllocError)
60        }
61    }
62
63    unsafe fn deallocate(&self, _ptr: NonNull<u8>, _layout: Layout) {
64        // intentionally empty
65    }
66
67    unsafe fn grow(
68        &self,
69        ptr: NonNull<u8>,
70        old_layout: Layout,
71        new_layout: Layout,
72    ) -> Result<NonNull<[u8]>, AllocError> {
73        self.grow_zeroed(ptr, old_layout, new_layout)
74    }
75
76    unsafe fn grow_zeroed(
77        &self,
78        ptr: NonNull<u8>,
79        old_layout: Layout,
80        new_layout: Layout,
81    ) -> Result<NonNull<[u8]>, AllocError> {
82        debug_assert!(
83            new_layout.size() >= old_layout.size(),
84            "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
85        );
86        if new_layout.size() > old_layout.size()
87            || (ptr.as_ptr() as usize & (new_layout.align() - 1) != 0)
88        {
89            return Err(AllocError);
90        }
91
92        let new_ptr = NonNull::slice_from_raw_parts(ptr, new_layout.size());
93
94        Ok(new_ptr)
95    }
96
97    unsafe fn shrink(
98        &self,
99        ptr: NonNull<u8>,
100        old_layout: Layout,
101        new_layout: Layout,
102    ) -> Result<NonNull<[u8]>, AllocError> {
103        debug_assert!(
104            new_layout.size() <= old_layout.size(),
105            "`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
106        );
107
108        if new_layout.size() > old_layout.size()
109            || (ptr.as_ptr() as usize & (new_layout.align() - 1) != 0)
110        {
111            return Err(AllocError);
112        }
113
114        let new_ptr = NonNull::slice_from_raw_parts(ptr, new_layout.size());
115
116        Ok(new_ptr)
117    }
118}
119
120#[cfg(feature = "alloc")]
121pub mod owning_ref;
122#[cfg(feature = "alloc")]
123pub mod owning_slice;