Struct r3_core::utils::ConstAllocator
source · pub struct ConstAllocator { /* private fields */ }
Expand description
Compile-time allocator.
This is implemented on top of core::intrinsics::const_allocate
.
Stability
This type is subject to the kernel-side API stability guarantee.
Implementations§
source§impl ConstAllocator
impl ConstAllocator
sourcepub const fn with<F, R>(f: F) -> Rwhere
F: FnOnce(&ConstAllocator) -> R,
pub const fn with<F, R>(f: F) -> Rwhere F: FnOnce(&ConstAllocator) -> R,
Call the specified closure, passing a reference to a Self
constructed
on the stack.
Does not work at runtime.
All clones of Self
and all allocations must be destroyed before the
closure returns. This is because leaking const-allocated
(interior-)mutable references to runtime code is unsound. See
https://github.com/rust-lang/rust/pull/91884#discussion_r774659436.
Examples
#![feature(const_eval_limit)]
#![feature(const_trait_impl)]
#![feature(const_mut_refs)]
#![feature(const_option)]
#![const_eval_limit = "500000"]
use core::{alloc::Layout, ptr::NonNull};
use r3_core::utils::{ConstAllocator, Allocator};
const _: () = ConstAllocator::with(doit);
const fn doit(al: &ConstAllocator) {
// You can clone `*al`, but you must destroy the clone before this
// function returns
let al = al.clone();
unsafe {
let mut blocks = [None; 256];
let mut i = 0;
while i < blocks.len() {
// Allocate a memory block
let Ok(layout) = Layout::from_size_align(i * 64, 8) else { unreachable!() };
let Ok(alloc) = al.allocate(layout) else { unreachable!() };
// Write something
let alloc = alloc.cast::<u8>();
if i > 0 { *alloc.as_ptr() = i as u8; }
// Remember the allocation
blocks[i] = Some((alloc, layout));
i += 1;
}
i = 1;
while i < blocks.len() {
// Check the value inside the allocation
let (ptr, _) = blocks[i].unwrap();
assert!(*ptr.as_ptr() == i as u8);
i += 1;
}
// You must deallocate all allocations before this
// function returns
i = 0;
while i < blocks.len() {
let (ptr, layout) = blocks[i].unwrap();
al.deallocate(ptr, layout);
i += 1;
}
}
}
It’s an error to leak allocations:
ⓘ
const fn doit(al: &ConstAllocator) {
let Ok(layout) = Layout::from_size_align(64, 8) else { unreachable!() };
let _ = al.allocate(layout);
}
ⓘ
const fn doit(al: &ConstAllocator) {
core::mem::forget(al.clone());
}
sourcepub const fn with_parametric<P, F, R>(p: P, f: F) -> Rwhere
F: FnOnce(P, &ConstAllocator) -> R,
pub const fn with_parametric<P, F, R>(p: P, f: F) -> Rwhere F: FnOnce(P, &ConstAllocator) -> R,
The variant of Self::with
that lets you pass an additional parameter
to the closure.
This can be used to work around the lack of compiler support for const closures.
Trait Implementations§
source§impl Allocator for ConstAllocator
impl Allocator for ConstAllocator
source§const fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>
const fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>
Attempts to allocate a block of memory.
source§const unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout)
const unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout)
Deallocates the memory referenced by
ptr
. Read moresource§fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>
Behaves like
allocate
, but also ensures that the returned memory is
zero-initialized.source§unsafe fn grow(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout
) -> Result<NonNull<[u8]>, AllocError>
unsafe fn grow( &self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout ) -> Result<NonNull<[u8]>, AllocError>
Attempts to extend the memory block. Read more
source§unsafe fn grow_zeroed(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout
) -> Result<NonNull<[u8]>, AllocError>
unsafe fn grow_zeroed( &self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout ) -> Result<NonNull<[u8]>, AllocError>
Behaves like
grow
, but also ensures that the new contents are set to
zero before being returned. Read more