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
48unsafe impl Allocator for NoopAllocator<'_> {
49    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
50        if layout.size() == 0 {
51            Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0))
52        } else {
53            Err(AllocError)
54        }
55    }
56
57    unsafe fn deallocate(&self, _ptr: NonNull<u8>, _layout: Layout) {
58        // intentionally empty
59    }
60
61    unsafe fn grow(
62        &self,
63        ptr: NonNull<u8>,
64        old_layout: Layout,
65        new_layout: Layout,
66    ) -> Result<NonNull<[u8]>, AllocError> {
67        self.grow_zeroed(ptr, old_layout, new_layout)
68    }
69
70    unsafe fn grow_zeroed(
71        &self,
72        ptr: NonNull<u8>,
73        old_layout: Layout,
74        new_layout: Layout,
75    ) -> Result<NonNull<[u8]>, AllocError> {
76        debug_assert!(
77            new_layout.size() >= old_layout.size(),
78            "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
79        );
80        if new_layout.size() > old_layout.size()
81            || (ptr.as_ptr() as usize & (new_layout.align() - 1) != 0)
82        {
83            return Err(AllocError);
84        }
85
86        let new_ptr = NonNull::slice_from_raw_parts(ptr, new_layout.size());
87
88        Ok(new_ptr)
89    }
90
91    unsafe fn shrink(
92        &self,
93        ptr: NonNull<u8>,
94        old_layout: Layout,
95        new_layout: Layout,
96    ) -> Result<NonNull<[u8]>, AllocError> {
97        debug_assert!(
98            new_layout.size() <= old_layout.size(),
99            "`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
100        );
101
102        if new_layout.size() > old_layout.size()
103            || (ptr.as_ptr() as usize & (new_layout.align() - 1) != 0)
104        {
105            return Err(AllocError);
106        }
107
108        let new_ptr = NonNull::slice_from_raw_parts(ptr, new_layout.size());
109
110        Ok(new_ptr)
111    }
112}
113
114#[cfg(feature = "alloc")]
115pub mod owning_ref;
116#[cfg(feature = "alloc")]
117pub mod owning_slice;